Création/mise à jour basique d'un DAD #15

Manually merged
wpetit merged 7 commits from feature/dad into develop 2020-08-26 14:52:54 +02:00
16 changed files with 254 additions and 13 deletions
Showing only changes of commit fc4912882a - Show all commits

View File

@ -3,6 +3,7 @@ import { BrowserRouter, Route, Redirect, Switch } from "react-router-dom";
import { HomePage } from './HomePage/HomePage'; import { HomePage } from './HomePage/HomePage';
import { ProfilePage } from './ProfilePage/ProfilePage'; import { ProfilePage } from './ProfilePage/ProfilePage';
import { WorkgroupPage } from './WorkgroupPage/WorkgroupPage'; import { WorkgroupPage } from './WorkgroupPage/WorkgroupPage';
import { DecisionSupportFilePage } from './DecisionSupportFilePage/DecisionSupportFilePage';
export class App extends React.Component { export class App extends React.Component {
render() { render() {
@ -12,6 +13,7 @@ export class App extends React.Component {
<Route path="/" exact component={HomePage} /> <Route path="/" exact component={HomePage} />
<Route path="/profile" exact component={ProfilePage} /> <Route path="/profile" exact component={ProfilePage} />
<Route path="/workgroups/:id" exact component={WorkgroupPage} /> <Route path="/workgroups/:id" exact component={WorkgroupPage} />
<Route path="/decisions/:id" exact component={DecisionSupportFilePage} />
<Route component={() => <Redirect to="/" />} /> <Route component={() => <Redirect to="/" />} />
</Switch> </Switch>
</BrowserRouter> </BrowserRouter>

View File

@ -0,0 +1,18 @@
import React, { FunctionComponent, useState } from 'react';
import { DecisionSupportFile } from '../../types/decision';
export interface AppendixPanelProps {
dsf: DecisionSupportFile,
};
export const AppendixPanel: FunctionComponent<AppendixPanelProps> = ({ dsf }) => {
return (
<nav className="panel">
<p className="panel-heading">
Annexes
</p>
<div className="panel-block">
</div>
</nav>
);
};

View File

@ -0,0 +1,67 @@
import React, { FunctionComponent, useState } from 'react';
import { DecisionSupportFile } from '../../types/decision';
export interface ClarificationSectionProps {
dsf: DecisionSupportFile,
};
export const ClarificationSection: FunctionComponent<ClarificationSectionProps> = ({ dsf }) => {
return (
<section>
<div className="box">
<div className="field">
<label className="label">Intitulé du dossier</label>
<div className="control">
<input className="input" type="text" />
</div>
</div>
<div className="field">
<label className="label">Quelle décision devons nous prendre ?</label>
<div className="control">
<textarea className="textarea" placeholder="Décrire globalement les tenants et aboutissants de la décision à prendre." rows={10}></textarea>
</div>
<p className="help is-info"><i className="fa fa-info-circle"></i> Ne pas essayer de rentrer trop dans les détails ici. Préférer l'utilisation des annexes et y faire référence.</p>
</div>
<div className="field">
<label className="label">Pourquoi devons nous prendre cette décision ?</label>
<div className="control">
<textarea className="textarea" placeholder="Décrire pourquoi il est important de prendre cette décision." rows={10}></textarea>
</div>
<p className="help is-info"><i className="fa fa-info-circle"></i> Penser à indiquer si des obligations légales pèsent sur cette prise de décision.</p>
</div>
<div className="field">
<label className="label">Portée de la décision</label>
<div className="control">
<div className="select">
<select>
<option></option>
<option>Individuelle</option>
<option>Groupe identifié</option>
<option>Collective</option>
</select>
</div>
</div>
</div>
<div className="field">
<label className="label">Nature de la décision</label>
<div className="control">
<div className="select">
<select>
<option></option>
<option>Opérationnelle</option>
<option>Tactique</option>
<option>Stratégique</option>
</select>
</div>
</div>
</div>
<div className="field">
<label className="label">Existe t'il une échéance particulière pour cette décision ?</label>
<div className="control">
<input className="input" type="date" />
</div>
</div>
</div>
</section>
);
};

View File

@ -0,0 +1,74 @@
import React, { FunctionComponent, useState } from 'react';
import { Page } from '../Page';
import { ClarificationSection } from './ClarificationSection';
import { OptionsSection } from './OptionsSection';
import { MetadataPanel } from './MetadataPanel';
import { AppendixPanel } from './AppendixPanel';
export interface DecisionSupportFilePageProps {
};
export const DecisionSupportFilePage: FunctionComponent<DecisionSupportFilePageProps> = () => {
const [ state, setState ] = useState({ dsf: null });
const isNew = true;
const isClosed = false;
return (
<Page title="Dossier d'Aide à la Décision">
<div className="container is-fluid">
<section className="mt-5">
<div className="level">
<div className="level-left">
{
isNew ?
<div className="level-item">
<div>
<h2 className="is-size-3 title is-spaced">Nouveau</h2>
<h3 className="is-size-5 subtitle">Dossier d'Aide à la Décision</h3>
</div>
</div> :
<div className="level-item">
<div>
<h2 className="is-size-3 title is-spaced">{state.dsf.title}</h2>
<h3 className="is-size-5 subtitle">Dossier d'Aide à la Décision <span className="is-italic">{ isClosed ? '(clos)' : null }</span></h3>
</div>
</div>
}
</div>
</div>
</section>
<div className="columns mt-3">
<div className="column is-9">
<div className="tabs is-medium is-toggle has-background-white">
<ul>
<li className="is-active">
<a>
<span className="icon is-small"><i className="fas fa-pen" aria-hidden="true"></i></span>
<span>Clarifier la décision</span>
</a>
</li>
<li>
<a>
<span className="icon is-small"><i className="fas fa-search" aria-hidden="true"></i></span>
<span>Explorer les options</span>
</a>
</li>
<li>
<a>
<span className="icon is-small"><i className="fas fa-person-booth" aria-hidden="true"></i></span>
<span>Prendre la décision</span>
</a>
</li>
</ul>
</div>
<ClarificationSection dsf={state.dsf} />
</div>
<div className="column is-3">
<MetadataPanel dsf={state.dsf} />
<AppendixPanel dsf={state.dsf} />
</div>
</div>
</div>
</Page>
);
};

View File

@ -0,0 +1,54 @@
import React, { FunctionComponent, useState } from 'react';
import { DecisionSupportFile } from '../../types/decision';
export interface MetadataPanelProps {
dsf: DecisionSupportFile,
};
export const MetadataPanel: FunctionComponent<MetadataPanelProps> = ({ dsf }) => {
return (
<nav className="panel">
<p className="panel-heading">
Métadonnées
</p>
<div className="panel-block">
<div style={{width:'100%'}}>
<div className="field">
<div className="label">Groupe de travail</div>
<div className="control is-expanded">
<div className="select is-fullwidth">
<select>
<option></option>
</select>
</div>
</div>
</div>
<div className="field">
<div className="label">Statut</div>
<div className="control is-expanded">
<div className="select is-fullwidth">
<select>
<option>En préparation</option>
<option>Prêt à voter</option>
<option>Voté</option>
</select>
</div>
</div>
</div>
<div className="field">
<div className="label">Créé le</div>
<div className="control">
<p>--</p>
</div>
</div>
<div className="field">
<div className="label">Dernière modification</div>
<div className="control">
<p>--</p>
</div>
</div>
</div>
</div>
</nav>
);
};

View File

@ -0,0 +1,17 @@
import React, { FunctionComponent, useState } from 'react';
import { DecisionSupportFile } from '../../types/decision';
export interface OptionsSectionProps {
dsf: DecisionSupportFile,
};
export const OptionsSection: FunctionComponent<OptionsSectionProps> = ({ dsf }) => {
return (
<section>
<h4 id="options-section" className="is-size-4 title is-spaced"><a href="#options-section">Explorer les options</a></h4>
<div className="box">
</div>
</section>
);
};

View File

@ -31,7 +31,7 @@ export function DecisionSupportFilePanel() {
return ( return (
<ItemPanel <ItemPanel
className='is-link' className='is-link'
title="Dossiers d'Aide à la Décision" title="D.A.D."
newItemUrl="/decisions/new" newItemUrl="/decisions/new"
items={decisions} items={decisions}
tabs={tabs} tabs={tabs}

View File

@ -78,7 +78,7 @@ export const ItemPanel: FunctionComponent<ItemPanelProps> = (props) => {
return ( return (
<nav className={`panel ${className}`}> <nav className={`panel ${className}`}>
<div className="level panel-heading mb-0"> <div className="level is-mobile panel-heading mb-0">
<div className="level-left"> <div className="level-left">
<p className="level-item">{title}</p> <p className="level-item">{title}</p>
</div> </div>

View File

@ -15,7 +15,7 @@ export function Navbar() {
}; };
return ( return (
<nav className="navbar" role="navigation" aria-label="main navigation"> <nav className="navbar is-fixed-top" role="navigation" aria-label="main navigation">
<div className="container is-fluid"> <div className="container is-fluid">
<div className="navbar-brand"> <div className="navbar-brand">
<Link className="navbar-item" to="/"> <Link className="navbar-item" to="/">

View File

@ -1,6 +1,6 @@
import { gql, useQuery, useMutation } from '@apollo/client'; import { gql, useQuery, useMutation } from '@apollo/client';
const MUTATION_UPDATE_USER_PROFILE = gql` export const MUTATION_UPDATE_USER_PROFILE = gql`
mutation updateUserProfile($changes: ProfileChanges!) { mutation updateUserProfile($changes: ProfileChanges!) {
updateProfile(changes: $changes) { updateProfile(changes: $changes) {
id, id,

View File

@ -1,6 +1,7 @@
import { gql, useQuery, useMutation } from '@apollo/client'; import { gql, useQuery, useMutation } from '@apollo/client';
import { QUERY_WORKGROUP } from '../queries/workgroups';
const MUTATION_UPDATE_WORKGROUP = gql` export const MUTATION_UPDATE_WORKGROUP = gql`
mutation updateWorkgroup($workgroupId: ID!, $changes: WorkgroupChanges!) { mutation updateWorkgroup($workgroupId: ID!, $changes: WorkgroupChanges!) {
updateWorkgroup(workgroupId: $workgroupId, changes: $changes) { updateWorkgroup(workgroupId: $workgroupId, changes: $changes) {
id, id,
@ -19,7 +20,7 @@ export function useUpdateWorkgroupMutation() {
return useMutation(MUTATION_UPDATE_WORKGROUP); return useMutation(MUTATION_UPDATE_WORKGROUP);
} }
const MUTATION_CREATE_WORKGROUP = gql` export const MUTATION_CREATE_WORKGROUP = gql`
mutation createWorkgroup($changes: WorkgroupChanges!) { mutation createWorkgroup($changes: WorkgroupChanges!) {
createWorkgroup(changes: $changes) { createWorkgroup(changes: $changes) {
id, id,
@ -35,10 +36,12 @@ mutation createWorkgroup($changes: WorkgroupChanges!) {
}`; }`;
export function useCreateWorkgroupMutation() { export function useCreateWorkgroupMutation() {
return useMutation(MUTATION_CREATE_WORKGROUP); return useMutation(MUTATION_CREATE_WORKGROUP, {
refetchQueries: [{query: QUERY_WORKGROUP}],
});
} }
const MUTATION_JOIN_WORKGROUP = gql` export const MUTATION_JOIN_WORKGROUP = gql`
mutation joinWorkgroup($workgroupId: ID!) { mutation joinWorkgroup($workgroupId: ID!) {
joinWorkgroup(workgroupId: $workgroupId) { joinWorkgroup(workgroupId: $workgroupId) {
id, id,

View File

@ -3,7 +3,7 @@ import { DecisionSupportFile } from '../../types/decision';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useGraphQLData } from './helper'; import { useGraphQLData } from './helper';
const QUERY_DECISIONS = gql` export const QUERY_DECISIONS = gql`
query decisions($filter: DecisionFilter) { query decisions($filter: DecisionFilter) {
decisions(filter: $filter) { decisions(filter: $filter) {
id, id,

View File

@ -3,7 +3,7 @@ import { User } from '../../types/user';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useGraphQLData } from './helper'; import { useGraphQLData } from './helper';
const QUERY_USER_PROFILE = gql` export const QUERY_USER_PROFILE = gql`
query userProfile { query userProfile {
userProfile { userProfile {
id, id,

View File

@ -2,7 +2,7 @@ import { gql, useQuery } from '@apollo/client';
import { Workgroup } from '../../types/workgroup'; import { Workgroup } from '../../types/workgroup';
import { useGraphQLData } from './helper'; import { useGraphQLData } from './helper';
const QUERY_WORKGROUP = gql` export const QUERY_WORKGROUP = gql`
query workgroups($filter: WorkgroupsFilter) { query workgroups($filter: WorkgroupsFilter) {
workgroups(filter: $filter) { workgroups(filter: $filter) {
id, id,

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en" class="has-navbar-fixed-top">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

View File

@ -1,6 +1,8 @@
html, body { html, body {
height: 100%; height: 100%;
background-color: #f7f7f7; background-color: #ffffff;
// Generated with https://www.svgbackgrounds.com/
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='351' height='292.5' viewBox='0 0 1080 900'%3E%3Cg fill-opacity='0.04'%3E%3Cpolygon fill='%23444' points='90 150 0 300 180 300'/%3E%3Cpolygon points='90 150 180 0 0 0'/%3E%3Cpolygon fill='%23AAA' points='270 150 360 0 180 0'/%3E%3Cpolygon fill='%23DDD' points='450 150 360 300 540 300'/%3E%3Cpolygon fill='%23999' points='450 150 540 0 360 0'/%3E%3Cpolygon points='630 150 540 300 720 300'/%3E%3Cpolygon fill='%23DDD' points='630 150 720 0 540 0'/%3E%3Cpolygon fill='%23444' points='810 150 720 300 900 300'/%3E%3Cpolygon fill='%23FFF' points='810 150 900 0 720 0'/%3E%3Cpolygon fill='%23DDD' points='990 150 900 300 1080 300'/%3E%3Cpolygon fill='%23444' points='990 150 1080 0 900 0'/%3E%3Cpolygon fill='%23DDD' points='90 450 0 600 180 600'/%3E%3Cpolygon points='90 450 180 300 0 300'/%3E%3Cpolygon fill='%23666' points='270 450 180 600 360 600'/%3E%3Cpolygon fill='%23AAA' points='270 450 360 300 180 300'/%3E%3Cpolygon fill='%23DDD' points='450 450 360 600 540 600'/%3E%3Cpolygon fill='%23999' points='450 450 540 300 360 300'/%3E%3Cpolygon fill='%23999' points='630 450 540 600 720 600'/%3E%3Cpolygon fill='%23FFF' points='630 450 720 300 540 300'/%3E%3Cpolygon points='810 450 720 600 900 600'/%3E%3Cpolygon fill='%23DDD' points='810 450 900 300 720 300'/%3E%3Cpolygon fill='%23AAA' points='990 450 900 600 1080 600'/%3E%3Cpolygon fill='%23444' points='990 450 1080 300 900 300'/%3E%3Cpolygon fill='%23222' points='90 750 0 900 180 900'/%3E%3Cpolygon points='270 750 180 900 360 900'/%3E%3Cpolygon fill='%23DDD' points='270 750 360 600 180 600'/%3E%3Cpolygon points='450 750 540 600 360 600'/%3E%3Cpolygon points='630 750 540 900 720 900'/%3E%3Cpolygon fill='%23444' points='630 750 720 600 540 600'/%3E%3Cpolygon fill='%23AAA' points='810 750 720 900 900 900'/%3E%3Cpolygon fill='%23666' points='810 750 900 600 720 600'/%3E%3Cpolygon fill='%23999' points='990 750 900 900 1080 900'/%3E%3Cpolygon fill='%23999' points='180 0 90 150 270 150'/%3E%3Cpolygon fill='%23444' points='360 0 270 150 450 150'/%3E%3Cpolygon fill='%23FFF' points='540 0 450 150 630 150'/%3E%3Cpolygon points='900 0 810 150 990 150'/%3E%3Cpolygon fill='%23222' points='0 300 -90 450 90 450'/%3E%3Cpolygon fill='%23FFF' points='0 300 90 150 -90 150'/%3E%3Cpolygon fill='%23FFF' points='180 300 90 450 270 450'/%3E%3Cpolygon fill='%23666' points='180 300 270 150 90 150'/%3E%3Cpolygon fill='%23222' points='360 300 270 450 450 450'/%3E%3Cpolygon fill='%23FFF' points='360 300 450 150 270 150'/%3E%3Cpolygon fill='%23444' points='540 300 450 450 630 450'/%3E%3Cpolygon fill='%23222' points='540 300 630 150 450 150'/%3E%3Cpolygon fill='%23AAA' points='720 300 630 450 810 450'/%3E%3Cpolygon fill='%23666' points='720 300 810 150 630 150'/%3E%3Cpolygon fill='%23FFF' points='900 300 810 450 990 450'/%3E%3Cpolygon fill='%23999' points='900 300 990 150 810 150'/%3E%3Cpolygon points='0 600 -90 750 90 750'/%3E%3Cpolygon fill='%23666' points='0 600 90 450 -90 450'/%3E%3Cpolygon fill='%23AAA' points='180 600 90 750 270 750'/%3E%3Cpolygon fill='%23444' points='180 600 270 450 90 450'/%3E%3Cpolygon fill='%23444' points='360 600 270 750 450 750'/%3E%3Cpolygon fill='%23999' points='360 600 450 450 270 450'/%3E%3Cpolygon fill='%23666' points='540 600 630 450 450 450'/%3E%3Cpolygon fill='%23222' points='720 600 630 750 810 750'/%3E%3Cpolygon fill='%23FFF' points='900 600 810 750 990 750'/%3E%3Cpolygon fill='%23222' points='900 600 990 450 810 450'/%3E%3Cpolygon fill='%23DDD' points='0 900 90 750 -90 750'/%3E%3Cpolygon fill='%23444' points='180 900 270 750 90 750'/%3E%3Cpolygon fill='%23FFF' points='360 900 450 750 270 750'/%3E%3Cpolygon fill='%23AAA' points='540 900 630 750 450 750'/%3E%3Cpolygon fill='%23FFF' points='720 900 810 750 630 750'/%3E%3Cpolygon fill='%23222' points='900 900 990 750 810 750'/%3E%3Cpolygon fill='%23222' points='1080 300 990 450 1170 450'/%3E%3Cpolygon fill='%23FFF' points='1080 300 1170 150 990 150'/%3E%3Cpolygon points='1080 600 990 750 1170 750'/%3E%3Cpolygon fill='%23666' points='1080 600 1170 450 990 450'/%3E%3Cpolygon fill='%23DDD' points='1080 900 1170 750 990 750'/%3E%3C/g%3E%3C/svg%3E");
} }
.is-fullheight { .is-fullheight {
@ -19,3 +21,7 @@ html, body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.panel {
background-color: #ffffff;
}