Remplacement de Redux/Saga par Apollo

This commit is contained in:
2020-07-21 22:25:39 +02:00
parent 8708e30020
commit c4373cce46
33 changed files with 230 additions and 728 deletions

View File

@ -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>
);
}
}

View File

@ -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() {

View File

@ -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">

View File

@ -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">

View File

@ -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>

View File

@ -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>

View File

@ -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,
}
});

View 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>
)
}