Remplacement de Redux/Saga par Apollo
This commit is contained in:
@ -1,22 +1,18 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter, Route, Redirect, Switch } from "react-router-dom";
|
||||
import { HomePage } from './HomePage/HomePage';
|
||||
import { store } from '../store/store';
|
||||
import { Provider } from 'react-redux';
|
||||
import { ProfilePage } from './ProfilePage/ProfilePage';
|
||||
|
||||
export class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<Switch>
|
||||
<Route path="/" exact component={HomePage} />
|
||||
<Route path="/profile" exact component={ProfilePage} />
|
||||
<Route component={() => <Redirect to="/" />} />
|
||||
</Switch>
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
<BrowserRouter>
|
||||
<Switch>
|
||||
<Route path="/" exact component={HomePage} />
|
||||
<Route path="/profile" exact component={ProfilePage} />
|
||||
<Route component={() => <Redirect to="/" />} />
|
||||
</Switch>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,7 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { fetchWorkgroups } from '../../store/actions/workgroups';
|
||||
import { RootState } from '../../store/reducers/root';
|
||||
import React from 'react';
|
||||
import { WorkgroupsPanel } from './WorkgroupsPanel';
|
||||
|
||||
export function Dashboard() {
|
||||
|
@ -1,18 +1,26 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { Page } from '../Page';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { RootState } from '../../store/reducers/root';
|
||||
import { Dashboard } from './Dashboard';
|
||||
import { useUserProfileQuery } from '../../gql/queries/profile';
|
||||
import { Loader } from '../Loader';
|
||||
|
||||
export function HomePage() {
|
||||
const currentUser = useSelector((state: RootState) => state.auth.currentUser);
|
||||
const { data, loading } = useUserProfileQuery();
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Loader />
|
||||
);
|
||||
}
|
||||
|
||||
const { userProfile } = (data || {});
|
||||
|
||||
return (
|
||||
<Page title={currentUser ? 'Tableau de bord' : 'Accueil'}>
|
||||
<Page title={userProfile ? 'Tableau de bord' : 'Accueil'}>
|
||||
<div className="container is-fluid">
|
||||
<section className="section">
|
||||
{
|
||||
currentUser ?
|
||||
userProfile ?
|
||||
<Dashboard /> :
|
||||
<div className="columns">
|
||||
<div className="column is-4 is-offset-4">
|
||||
|
@ -1,44 +1,49 @@
|
||||
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';
|
||||
import { useWorkgroupsQuery } from '../../gql/queries/workgroups';
|
||||
import { useUserProfileQuery } from '../../gql/queries/profile';
|
||||
import { Loader } from '../Loader';
|
||||
|
||||
export function WorkgroupsPanel() {
|
||||
const dispatch = useDispatch();
|
||||
const workgroups = useSelector<RootState>(state => state.workgroups.workgroupsById);
|
||||
const currentUserId = useSelector<RootState>(state => state.auth.currentUser.id);
|
||||
const workgroupsQuery = useWorkgroupsQuery();
|
||||
const userProfileQuery = useUserProfileQuery();
|
||||
const [ state, setState ] = useState({ selectedTab: 0 });
|
||||
|
||||
const isLoading = userProfileQuery.loading || workgroupsQuery.loading;
|
||||
if (isLoading) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
let { data: { userProfile }} = userProfileQuery;
|
||||
let { data: { workgroups }} = workgroupsQuery;
|
||||
|
||||
const filterTabs = [
|
||||
{
|
||||
label: "Mes groupes",
|
||||
filter: workgroups => Object.values(workgroups).filter((wg: Workgroup) => {
|
||||
return wg.members.some((u: User) => u.id === currentUserId);
|
||||
filter: workgroups => workgroups.filter((wg: Workgroup) => {
|
||||
return wg.members.some((u: User) => u.id === userProfile.id);
|
||||
})
|
||||
},
|
||||
{
|
||||
label: "Ouverts",
|
||||
filter: workgroups => Object.values(workgroups).filter((wg: Workgroup) => !wg.closedAt)
|
||||
filter: workgroups => workgroups.filter((wg: Workgroup) => !wg.closedAt)
|
||||
},
|
||||
{
|
||||
label: "Clôs",
|
||||
filter: workgroups => Object.values(workgroups).filter((wg: Workgroup) => !!wg.closedAt)
|
||||
filter: workgroups => 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) => {
|
||||
let workgroupsItems = [];
|
||||
|
||||
workgroupsItems = filterTabs[state.selectedTab].filter(workgroups).map((wg: Workgroup) => {
|
||||
return (
|
||||
<Link to={`/workgroups/${wg.id}`} key={`wg-${wg.id}`} className="panel-block">
|
||||
<span className="panel-icon">
|
||||
@ -47,7 +52,7 @@ export function WorkgroupsPanel() {
|
||||
{wg.name}
|
||||
</Link>
|
||||
);
|
||||
})
|
||||
});
|
||||
|
||||
return (
|
||||
<nav className="panel is-info">
|
||||
|
@ -1,13 +1,13 @@
|
||||
import React, { Fragment, useState } from 'react';
|
||||
import logo from '../resources/logo.svg';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { RootState } from '../store/reducers/root';
|
||||
import { Config } from '../config';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useUserProfileQuery } from '../gql/queries/profile';
|
||||
import { WithLoader } from './WithLoader';
|
||||
|
||||
export function Navbar() {
|
||||
const isAuthenticated = useSelector<RootState>(state => state.auth.isAuthenticated);
|
||||
|
||||
const userProfileQuery = useUserProfileQuery();
|
||||
const [ isActive, setActive ] = useState(false);
|
||||
|
||||
const toggleMenu = () => {
|
||||
@ -35,28 +35,30 @@ export function Navbar() {
|
||||
<div className={`navbar-menu ${isActive ? 'is-active' : ''}`}>
|
||||
<div className="navbar-end">
|
||||
<div className="navbar-item">
|
||||
<div className="buttons">
|
||||
{
|
||||
isAuthenticated ?
|
||||
<Fragment>
|
||||
<Link to="/profile" className="button">
|
||||
<WithLoader loading={userProfileQuery.loading}>
|
||||
<div className="buttons">
|
||||
{
|
||||
userProfileQuery.data && userProfileQuery.data.userProfile ?
|
||||
<Fragment>
|
||||
<Link to="/profile" className="button">
|
||||
<span className="icon">
|
||||
<i className="fas fa-user"></i>
|
||||
</span>
|
||||
</Link>
|
||||
<a className="button" href={Config.logoutURL}>
|
||||
<span className="icon">
|
||||
<i className="fas fa-sign-out-alt"></i>
|
||||
</span>
|
||||
</a>
|
||||
</Fragment> :
|
||||
<a className="button" href={Config.loginURL}>
|
||||
<span className="icon">
|
||||
<i className="fas fa-user"></i>
|
||||
</span>
|
||||
</Link>
|
||||
<a className="button" href={Config.logoutURL}>
|
||||
<span className="icon">
|
||||
<i className="fas fa-sign-out-alt"></i>
|
||||
<i className="fas fa-sign-in-alt"></i>
|
||||
</span>
|
||||
</a>
|
||||
</Fragment> :
|
||||
<a className="button" href={Config.loginURL}>
|
||||
<span className="icon">
|
||||
<i className="fas fa-sign-in-alt"></i>
|
||||
</span>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</WithLoader>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,19 +1,22 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { Page } from '../Page';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { RootState } from '../../store/reducers/root';
|
||||
import { UserForm } from '../UserForm';
|
||||
import { Loader } from '../Loader';
|
||||
import { User } from '../../types/user';
|
||||
import { updateProfile } from '../../store/actions/profile';
|
||||
import { useUserProfileQuery } from '../../gql/queries/profile';
|
||||
import { useUpdateUserProfileMutation } from '../../gql/mutations/profile';
|
||||
import { WithLoader } from '../WithLoader';
|
||||
|
||||
export function ProfilePage() {
|
||||
const currentUser = useSelector((state: RootState) => state.auth.currentUser);
|
||||
const dispatch = useDispatch();
|
||||
const userProfileQuery = useUserProfileQuery();
|
||||
const [ updatProfile, updateUserProfileMutation ] = useUpdateUserProfileMutation();
|
||||
const isLoading = updateUserProfileMutation.loading || userProfileQuery.loading;
|
||||
|
||||
const { userProfile } = (userProfileQuery.data || {});
|
||||
|
||||
const onUserChange = (user: User) => {
|
||||
if (currentUser.name !== user.name) {
|
||||
dispatch(updateProfile({ name: user.name }))
|
||||
if (userProfile.name !== user.name) {
|
||||
updatProfile({ variables: {changes: { name: user.name }}});
|
||||
}
|
||||
};
|
||||
|
||||
@ -24,11 +27,13 @@ export function ProfilePage() {
|
||||
<div className="columns">
|
||||
<div className="column is-6 is-offset-3">
|
||||
<h2 className="is-size-2 subtitle">Mon profil</h2>
|
||||
<WithLoader loading={isLoading}>
|
||||
{
|
||||
currentUser ?
|
||||
<UserForm onChange={onUserChange} user={currentUser} /> :
|
||||
userProfile ?
|
||||
<UserForm onChange={onUserChange} user={userProfile} /> :
|
||||
<Loader />
|
||||
}
|
||||
</WithLoader>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -10,11 +10,11 @@ export function UserForm({ user, onChange }: UserFormProps) {
|
||||
const [ state, setState ] = useState({
|
||||
changed: false,
|
||||
user: {
|
||||
name: '',
|
||||
email: '',
|
||||
createdAt: null,
|
||||
connectedAt: null,
|
||||
...user,
|
||||
id: user && user.id ? user.id : '',
|
||||
name: user && user.name ? user.name : '',
|
||||
email: user && user.email ? user.email : '',
|
||||
createdAt: user && user.createdAt ? user.createdAt : null,
|
||||
connectedAt: user && user.connectedAt ? user.connectedAt : null,
|
||||
}
|
||||
});
|
||||
|
||||
|
22
client/src/components/WithLoader.tsx
Normal file
22
client/src/components/WithLoader.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import React, { Fragment, PropsWithChildren, FunctionComponent } from 'react';
|
||||
|
||||
export interface WithLoaderProps {
|
||||
loading?: boolean
|
||||
}
|
||||
|
||||
export const WithLoader: FunctionComponent<WithLoaderProps> = ({ loading, children }) => {
|
||||
return (
|
||||
<Fragment>
|
||||
{
|
||||
loading ?
|
||||
<div className="loader-container">
|
||||
<div className="lds-ripple">
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div> :
|
||||
children
|
||||
}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user