Skip to content

Commit

Permalink
feat(cip-1694): restyle voting page
Browse files Browse the repository at this point in the history
  • Loading branch information
vetalcore committed Jul 26, 2023
1 parent 9aeab1d commit 2f58f55
Show file tree
Hide file tree
Showing 42 changed files with 938 additions and 618 deletions.
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,39 @@ Voltaire Voting Applications to be used by Cardano Community to cast CIP-1694 pr
- Docker-Compose

## Running (Development)

- create `.env` file on the same level as `.env.development`

```shell
brew install maven
```

```shell
git clone git@github.com:cardano-foundation/merkle-tree-java.git
mvn clean install
```

```shell
docker-compose up -d
git clone https://github.com/cardano-foundation/cip30-data-signature-parser
mvn install clean
```

```shell
cd cf-voting-app
rm -rf db
docker-compose rm
docker-compose up
```

```shell
cd cf-voting-app/backend-services/voting-app
./gradlew bootRun
```

```shell
npm run start
```

## Repository Structure
- service - contains java backend code needed for the frontend
- ui - contains React.JS frontend code to cast votes / display voting results
16 changes: 16 additions & 0 deletions ui/cip-1694/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
REACT_APP_VERSION=$npm_package_version
REACT_APP_SERVER_URL="http://localhost:3000"
REACT_APP_TARGET_NETWORK=PREPROD

REACT_APP_EVENT_ID=CIP-1694_Pre_Ratification_4619
REACT_APP_CATEGORY_ID=CIP-1694_Pre_Ratification_4619

REACT_APP_EVENT_BY_ID_REFERENCE_URL=${REACT_APP_SERVER_URL}/api/reference/event
REACT_APP_CAST_VOTE_URL=${REACT_APP_SERVER_URL}/api/vote/cast
REACT_APP_BLOCKCHAIN_TIP_URL=${REACT_APP_SERVER_URL}/api/blockchain/tip
REACT_APP_VOTING_POWER_URL=${REACT_APP_SERVER_URL}/api/account

REACT_APP_SUPPORTED_WALLETS=flint,eternl,nami,typhon,yoroi,nufi,gerowallet,lace
REACT_APP_ALWAYS_VISIBLE_WALLETS=lace
REACT_APP_EVENT_END_TIME=09-01-2023
REACT_APP_EVENT_END_TIME_FORMAT=MM-DD-YYYY
6 changes: 1 addition & 5 deletions ui/cip-1694/cypress/e2e/count-down-timer.cy.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
describe('count down timer spec', () => {
it('passes', () => {
cy.visit('http://localhost:3000/')
})
it('should timer exists', () => {
cy.visit('http://localhost:3000/');
cy.get('[data-testid="count-down-timer"]').contains("days");
});
})
});
5 changes: 5 additions & 0 deletions ui/cip-1694/src/App.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.toast {
border-radius: 10px;
background: #030321;
color: #fff;
}
35 changes: 12 additions & 23 deletions ui/cip-1694/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,22 @@
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { Toaster } from 'react-hot-toast';
import CssBaseline from '@mui/material/CssBaseline';
import { ThemeProvider } from '@mui/material/styles';
import { Layout } from 'components/common/Layout/Layout';
import Content from './components/common/Content/Content';
import { Footer } from './components/common/Footer/Footer';
import { Header } from './components/common/Header/Header';
import theme from './common/styles/theme';
import styles from './App.module.scss';

export const App = () => (
<ThemeProvider theme={theme}>
<Router>
<Layout>
<Header />
<Content />
<Footer />
<Toaster
toastOptions={{
className: '',
style: {
borderRadius: '10px',
background: '#030321',
color: '#fff',
},
}}
/>
<CssBaseline />
</Layout>
</Router>
</ThemeProvider>
<Layout>
<Header />
<Content />
<Footer />
<Toaster
toastOptions={{
className: styles.toast,
}}
/>
<CssBaseline />
</Layout>
);
4 changes: 2 additions & 2 deletions ui/cip-1694/src/common/api/voteService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
BLOCKCHAIN_TIP_URL,
VOTING_POWER_URL,
} from '../constants/appConstants';
import { Problem, SignedWeb3Request, Vote, Event, ChainTip } from '../../types/backend-services-types';
import { Problem, SignedWeb3Request, Vote, Event, ChainTip, Account } from '../../types/backend-services-types';

const getEventById = async (eventId: Event['id']) =>
await doRequest<Vote>(HttpMethods.GET, `${EVENT_BY_ID_REFERENCE_URL}/${eventId}`, {
Expand All @@ -26,7 +26,7 @@ const getSlotNumber = async () => {
};

const getVotingPower = async (eventId: Event['id'], stakeAddress: string) => {
return await doRequest<number>(HttpMethods.GET, `${VOTING_POWER_URL}/${eventId}/${stakeAddress}`, {
return await doRequest<Account>(HttpMethods.GET, `${VOTING_POWER_URL}/${eventId}/${stakeAddress}`, {
...DEFAULT_CONTENT_TYPE_HEADERS,
});
};
Expand Down
6 changes: 6 additions & 0 deletions ui/cip-1694/src/common/constants/appConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ export const TARGET_NETWORK = process.env.REACT_APP_TARGET_NETWORK;
export const EVENT_ID = process.env.REACT_APP_EVENT_ID;
export const CATEGORY_ID = process.env.REACT_APP_CATEGORY_ID;
export const COMMIT_HASH = process.env.REACT_APP_COMMIT_HASH;
export const SUPPORTED_WALLETS = (process.env.REACT_APP_SUPPORTED_WALLETS || '').split(',').filter((w) => !!w);
export const ALWAYS_VISIBLE_WALLETS = (process.env.REACT_APP_ALWAYS_VISIBLE_WALLETS || '')
.split(',')
.filter((w) => !!w);
export const EVENT_END_TIME = process.env.REACT_APP_EVENT_END_TIME; // summit date
export const EVENT_END_TIME_FORMAT = process.env.REACT_APP_EVENT_END_TIME_FORMAT;
18 changes: 2 additions & 16 deletions ui/cip-1694/src/common/handlers/httpHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,16 @@ export function responseErrorsHandler() {
};
}

type NoContentResponse = { status: number; message: string };
// type NoContentResponse = { status: number; message: string };
type Errors = { errors: Array<{ errorCode: string }> } & Omit<Response, 'errors'>;

export function responseHandlerDelegate<T>() {
const errorsHandler = responseErrorsHandler();

return {
async parse(response: Response | AnuthorizedResponse): Promise<T | NoContentResponse | never> {
async parse(response: Response | AnuthorizedResponse): Promise<T | never> {
let json!: T & Errors;

if (response.status === 204) {
return {
status: 204,
message: 'Success',
};
}

try {
json = await response.json();
} catch (err) {
Expand All @@ -125,13 +118,6 @@ export function responseHandlerDelegate<T>() {
}
}

if (json === undefined && response.status === 200) {
return {
status: 200,
message: 'Success',
};
}

if (typeof json === 'object' && 'errors' in json && json.errors.length >= 1) {
throw new HttpError(400, response.url, errorsHandler.parse(json.errors));
} else {
Expand Down
18 changes: 3 additions & 15 deletions ui/cip-1694/src/common/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
import { configureStore } from '@reduxjs/toolkit';
import { persistReducer, persistStore } from 'redux-persist';
import thunk from 'redux-thunk';
import reduxReset from 'redux-reset';
import storage from 'redux-persist/lib/storage';
import userSessionReducer from './userSlice';
import { State } from './types';

const userPersistConfig = {
key: 'user',
storage,
blacklist: ['isLoggedIn'],
};

export const store = configureStore({
reducer: persistReducer(userPersistConfig, userSessionReducer),
export const store = configureStore<State>({
reducer: { user: userSessionReducer },
devTools: process.env.NODE_ENV !== 'production',
middleware: [thunk, reduxReset],
});

export const persistor = persistStore(store);

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
12 changes: 7 additions & 5 deletions ui/cip-1694/src/common/store/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export interface UserState {
isLoggedIn: boolean;
isVerified: boolean;
termsAndPrivacy: boolean;
error: string;
user?: object;
isConnectWalletModalVisible: boolean;
isVoteSubmittedModalVisible: boolean;
connectedWallet: string;
}

export interface State {
user: UserState;
}
34 changes: 10 additions & 24 deletions ui/cip-1694/src/common/store/userSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,26 @@ import type { PayloadAction } from '@reduxjs/toolkit';
import { UserState } from './types';

const initialState: UserState = {
isLoggedIn: false,
isVerified: false,
termsAndPrivacy: false,
error: '',
isConnectWalletModalVisible: false,
isVoteSubmittedModalVisible: false,
connectedWallet: '',
};

export const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
setSession: (state, action: PayloadAction<{ session: object }>) => {
return {
...initialState,
...action.payload.session,
isLoggedIn: true,
};
setIsConnectWalletModalVisible: (state, action: PayloadAction<{ isVisible: boolean }>) => {
state.isConnectWalletModalVisible = action.payload.isVisible;
},
setUser: (state, action: PayloadAction<{ user: object }>) => {
state.user = action.payload.user;
setIsVoteSubmittedModalVisible: (state, action: PayloadAction<{ isVisible: boolean }>) => {
state.isVoteSubmittedModalVisible = action.payload.isVisible;
},
setUserIsVerified: (state, action: PayloadAction<{ isVerified: boolean }>) => {
state.isVerified = action.payload.isVerified;
},
reduxError: (state, action: PayloadAction<{ error: string }>) => {
state.error = action.payload.error;
},
clearSession: (state, action: PayloadAction<{ termsAndPrivacy: boolean }>) => {
return {
...initialState,
termsAndPrivacy: action.payload.termsAndPrivacy,
};
setConnectedWallet: (state, action: PayloadAction<{ wallet: string }>) => {
state.connectedWallet = action.payload.wallet;
},
},
});

export const { setSession, setUser, setUserIsVerified, reduxError, clearSession } = userSlice.actions;
export const { setIsConnectWalletModalVisible, setIsVoteSubmittedModalVisible, setConnectedWallet } = userSlice.actions;
export default userSlice.reducer;
2 changes: 1 addition & 1 deletion ui/cip-1694/src/common/utils/voteUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type voteInput = {
voteId: string;
voter: string;
slotNumber: string;
votePower: number;
votePower: string;
};

export const buildCanonicalVoteInputJson = ({ option, voteId, voter, slotNumber, votePower }: voteInput) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.dialogTitle {
background: #f5f9ff !important;
padding: 30px 30px 20px 30px !important;
color: #061d3c !important;
font-size: 28px !important;
font-style: normal !important;
font-weight: 600 !important;
line-height: normal !important;
}

.description {
color: #39486c !important;
font-size: 16px !important;
font-style: normal !important;
font-weight: 400 !important;
line-height: 22px !important;
}

.dialogContent {
background: #f5f9ff !important;
padding: 0px 30px 30px 30px !important;
}

.closeBtn {
background: #eee !important;
position: absolute !important;
right: 10px !important;
top: 10px !important;

.closeIcon {
color: #061d3c !important;
}
}
Loading

0 comments on commit 2f58f55

Please sign in to comment.