diff --git a/client/package-lock.json b/client/package-lock.json index 635b1c5..e23fc13 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -3235,9 +3235,9 @@ "dev": true }, "bulma": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.7.5.tgz", - "integrity": "sha512-cX98TIn0I6sKba/DhW0FBjtaDpxTelU166pf7ICXpCCuplHWyu6C9LYZmL5PEsnePIeJaiorsTEzzNk3Tsm1hw==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.9.0.tgz", + "integrity": "sha512-rV75CJkubNUroAt0qCRkjznZLoaXq/ctfMXsMvKSL84UetbSyx5REl96e8GoQ04G4Tkw0XF3STECffTOQrbzOQ==" }, "bulma-switch": { "version": "2.0.0", diff --git a/client/package.json b/client/package.json index d5cf484..a5edbbc 100644 --- a/client/package.json +++ b/client/package.json @@ -58,7 +58,7 @@ "apollo-link-http": "^1.5.17", "apollo-link-ws": "^1.0.20", "apollo-utilities": "^1.3.4", - "bulma": "^0.7.2", + "bulma": "^0.9.0", "bulma-switch": "^2.0.0", "graphql": "^15.3.0", "graphql-request": "^2.0.0", diff --git a/client/src/components/HomePage/Dashboard.tsx b/client/src/components/HomePage/Dashboard.tsx index 408087a..925ae03 100644 --- a/client/src/components/HomePage/Dashboard.tsx +++ b/client/src/components/HomePage/Dashboard.tsx @@ -1,25 +1,20 @@ -import React from 'react'; +import React, { useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { fetchWorkgroups } from '../../store/actions/workgroups'; +import { RootState } from '../../store/reducers/root'; +import { WorkgroupsPanel } from './WorkgroupsPanel'; export function Dashboard() { return (
-
-
-
-

Groupes de travail

-
-
- -
-
-
+
-

D.à.Ds

+

D.A.Ds

diff --git a/client/src/components/HomePage/WorkgroupsPanel.tsx b/client/src/components/HomePage/WorkgroupsPanel.tsx new file mode 100644 index 0000000..5e6f48a --- /dev/null +++ b/client/src/components/HomePage/WorkgroupsPanel.tsx @@ -0,0 +1,96 @@ +import React, { useEffect, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { RootState } from '../../store/reducers/root'; +import { fetchWorkgroups } from '../../store/actions/workgroups'; +import { Workgroup } from '../../types/workgroup'; +import { User } from '../../types/user'; +import { Link } from 'react-router-dom'; + +export function WorkgroupsPanel() { + const dispatch = useDispatch(); + const workgroups = useSelector(state => state.workgroups.workgroupsById); + const currentUserId = useSelector(state => state.auth.currentUser.id); + + const filterTabs = [ + { + label: "Mes groupes", + filter: workgroups => Object.values(workgroups).filter((wg: Workgroup) => { + return wg.members.some((u: User) => u.id === currentUserId); + }) + }, + { + label: "Ouverts", + filter: workgroups => Object.values(workgroups).filter((wg: Workgroup) => !wg.closedAt) + }, + { + label: "Clôs", + filter: workgroups => Object.values(workgroups).filter((wg: Workgroup) => !!wg.closedAt) + } + ]; + + const [ state, setState ] = useState({ selectedTab: 0 }); + + const selectTab = (tabIndex: number) => { + setState(state => ({ ...state, selectedTab: tabIndex })); + } + + useEffect(() => { + dispatch(fetchWorkgroups()); + }, []); + + const workgroupsItems = filterTabs[state.selectedTab].filter(workgroups).map((wg: Workgroup) => { + return ( + + + + + {wg.name} + + ); + }) + + return ( + + ) +} \ No newline at end of file diff --git a/client/src/store/actions/workgroups.ts b/client/src/store/actions/workgroups.ts new file mode 100644 index 0000000..6894390 --- /dev/null +++ b/client/src/store/actions/workgroups.ts @@ -0,0 +1,19 @@ +import { Action } from "redux"; +import { Workgroup } from "../../types/workgroup"; + +export const FETCH_WORKGROUPS_REQUEST = 'FETCH_WORKGROUPS_REQUEST'; +export const FETCH_WORKGROUPS_SUCCESS = 'FETCH_WORKGROUPS_SUCCESS'; +export const FETCH_WORKGROUPS_FAILURE = 'FETCH_WORKGROUPS_FAILURE'; + +export interface fetchWorkgroupsRequestAction extends Action { + +} + +export interface fetchWorkgroupsSuccessAction extends Action { + workgroups: [Workgroup] +} + + +export function fetchWorkgroups(): fetchWorkgroupsRequestAction { + return { type: FETCH_WORKGROUPS_REQUEST } +} \ No newline at end of file diff --git a/client/src/store/reducers/auth.ts b/client/src/store/reducers/auth.ts index 2192326..c37ba47 100644 --- a/client/src/store/reducers/auth.ts +++ b/client/src/store/reducers/auth.ts @@ -31,6 +31,7 @@ function handleSetCurrentUser(state: AuthState, { email }: setCurrentUserAction) ...state, isAuthenticated: true, currentUser: { + id: '', email } }; diff --git a/client/src/store/reducers/root.ts b/client/src/store/reducers/root.ts index 5835800..337b8b0 100644 --- a/client/src/store/reducers/root.ts +++ b/client/src/store/reducers/root.ts @@ -1,13 +1,16 @@ import { combineReducers } from 'redux'; import { flagsReducer, FlagsState } from './flags'; import { authReducer, AuthState } from './auth'; +import { workgroupsReducer, WorkgroupsState } from './workgroups'; export interface RootState { auth: AuthState, flags: FlagsState, + workgroups: WorkgroupsState, } export const rootReducer = combineReducers({ flags: flagsReducer, auth: authReducer, + workgroups: workgroupsReducer, }); \ No newline at end of file diff --git a/client/src/store/reducers/workgroups.ts b/client/src/store/reducers/workgroups.ts new file mode 100644 index 0000000..c692167 --- /dev/null +++ b/client/src/store/reducers/workgroups.ts @@ -0,0 +1,38 @@ +import { Action } from "redux"; +import { User } from "../../types/user"; +import { SET_CURRENT_USER, setCurrentUserAction } from "../actions/auth"; +import { FETCH_PROFILE_SUCCESS, fetchProfileSuccessAction, updateProfileSuccessAction, UPDATE_PROFILE_SUCCESS, updateProfileRequestAction } from "../actions/profile"; +import { Workgroup } from "../../types/workgroup"; +import { FETCH_WORKGROUPS_SUCCESS, fetchWorkgroupsSuccessAction } from "../actions/workgroups"; + +export interface WorkgroupsState { + workgroupsById: { [id in string]: Workgroup } +} + +const defaultState = { + workgroupsById: {} +}; + +export function workgroupsReducer(state = defaultState, action: Action): WorkgroupsState { + switch (action.type) { + case FETCH_WORKGROUPS_SUCCESS: + return handleFetchWorkgroups(state, action as fetchWorkgroupsSuccessAction); + + } + return state; +} + +function handleFetchWorkgroups(state: WorkgroupsState, { workgroups }: fetchWorkgroupsSuccessAction): WorkgroupsState { + const workgroupsById = { + ...state.workgroupsById, + }; + + workgroups.forEach(wg => { + workgroupsById[wg.id] = wg; + }); + + return { + ...state, + workgroupsById, + }; +}; \ No newline at end of file diff --git a/client/src/store/sagas/root.ts b/client/src/store/sagas/root.ts index 6a1c770..b09eca5 100644 --- a/client/src/store/sagas/root.ts +++ b/client/src/store/sagas/root.ts @@ -2,11 +2,13 @@ import { all } from 'redux-saga/effects'; import { failureRootSaga } from './failure'; import { initRootSaga } from './init'; import { profileRootSaga } from './profile'; +import { workgroupsRootSaga } from './workgroups'; export function* rootSaga() { yield all([ initRootSaga(), failureRootSaga(), profileRootSaga(), + workgroupsRootSaga(), ]); } diff --git a/client/src/store/sagas/workgroups.ts b/client/src/store/sagas/workgroups.ts new file mode 100644 index 0000000..a6d9cc3 --- /dev/null +++ b/client/src/store/sagas/workgroups.ts @@ -0,0 +1,25 @@ +import { getClient } from "../../util/daddy"; +import { Config } from "../../config"; +import { all, takeLatest, put } from "redux-saga/effects"; +import { FETCH_WORKGROUPS_SUCCESS, FETCH_WORKGROUPS_FAILURE, FETCH_WORKGROUPS_REQUEST } from "../actions/workgroups"; +import { Workgroup } from "../../types/workgroup"; + +export function* workgroupsRootSaga() { + yield all([ + takeLatest(FETCH_WORKGROUPS_REQUEST, fetchWorkgroupsSaga), + ]); +} + +export function* fetchWorkgroupsSaga() { + const client = getClient(Config.graphQLEndpoint, Config.subscriptionEndpoint); + + let workgroups: [Workgroup]; + try { + workgroups = yield client.fetchWorkgroups().then(result => result.workgroups); + } catch(err) { + yield put({ type: FETCH_WORKGROUPS_FAILURE, err }); + return; + } + + yield put({type: FETCH_WORKGROUPS_SUCCESS, workgroups }); +} \ No newline at end of file diff --git a/client/src/types/user.ts b/client/src/types/user.ts index 4fc773d..2fae681 100644 --- a/client/src/types/user.ts +++ b/client/src/types/user.ts @@ -1,4 +1,5 @@ export interface User { + id: string email: string name?: string connectedAt?: Date diff --git a/client/src/types/workgroup.ts b/client/src/types/workgroup.ts new file mode 100644 index 0000000..459f29a --- /dev/null +++ b/client/src/types/workgroup.ts @@ -0,0 +1,9 @@ +import { User } from "./user"; + +export interface Workgroup { + id: string + name: string + createdAt: Date + closedAt: Date + members: [User] +} \ No newline at end of file diff --git a/client/src/util/daddy.ts b/client/src/util/daddy.ts index 8c439fd..aa48178 100644 --- a/client/src/util/daddy.ts +++ b/client/src/util/daddy.ts @@ -79,6 +79,7 @@ export class DaddyClient { query: gql` query { userProfile { + id, name, email, createdAt, @@ -89,6 +90,24 @@ export class DaddyClient { .then(this.assertAuthorization) } + fetchWorkgroups() { + return this.gql.query({ + query: gql` + query { + workgroups { + id, + name, + createdAt, + closedAt, + members { + id + } + } + }` + }) + .then(this.assertAuthorization) + } + updateProfile(changes: ProfileChanges) { return this.gql.mutate({ variables: {