Add /profil to notifications, improve responsiveness

This commit is contained in:
pikiou 2022-03-25 01:37:11 +01:00
parent f65963d91c
commit 8fb7b5287b
21 changed files with 538 additions and 280 deletions

View File

@ -0,0 +1,53 @@
import { FC, ReactNode, useState } from "react"
import styles from "./styles.module.scss"
type Props = {
children?: ReactNode | undefined
text: string
onClick?: () => void
}
const FormButton: FC<Props> = ({ children, text, onClick }): JSX.Element => {
const [doShowMessage, setDoShowMessage] = useState<boolean>(false)
const showMessage = () => {
setDoShowMessage(true)
}
const onIgnore = () => {
setDoShowMessage(true)
onClick?.()
}
const onCloseIgnore = () => {
setDoShowMessage(false)
}
return (
<>
<button
type="button"
className={styles.greyButton}
onClick={!children ? onClick : showMessage}
>
{text}
</button>
{doShowMessage && (
<div className={styles.infoBeforeIgnore}>
<button type="button" className={styles.closeButton} onClick={onCloseIgnore}>
&#10005;
</button>
<div>{children}</div>
<button type="button" className={styles.greyButton} onClick={onIgnore}>
Ok, ignorer
</button>
</div>
)}
</>
)
}
FormButton.defaultProps = {
children: undefined,
onClick: undefined,
}
export default FormButton

View File

@ -0,0 +1,30 @@
@import "../../../theme/mixins";
.greyButton {
@include form-grey-button;
margin-top: 10px;
}
.infoBeforeIgnore {
margin-top: 15px;
position: relative;
padding: 15px;
outline: 0;
background-color: $color-white;
}
.closeButton {
position: absolute;
padding: 0;
z-index: 10;
top: 10px;
right: 10px;
width: 20px;
height: 20px;
border-radius: 0;
line-height: 20px;
color: $color-grey-dark;
text-align: center;
background: none;
cursor: pointer;
}

View File

@ -6,6 +6,7 @@ import styles from "./styles.module.scss"
const MainMenu: FC = (): JSX.Element | null => {
const connected = useSelector(isUserConnected)
const [opened, setOpened] = useState(false)
const onOpen = useCallback(() => {
@ -24,6 +25,9 @@ const MainMenu: FC = (): JSX.Element | null => {
</button>
<ul className={classnames(styles.mainMenu, opened && styles.opened)}>
<li className={styles.mainMenuItem}>
<a href="/">Page d'accueil</a>
</li>
<li className={styles.mainMenuItem}>
<a href="/annonces">Annonces</a>
</li>

View File

@ -57,6 +57,9 @@
text-align: center;
font-size: 22px;
color: $color-black;
background-color: $color-white;
border-radius: 4px;
box-shadow: 1px 1px 2px $color-black;
}
}

View File

@ -1,16 +1,25 @@
import _ from "lodash"
import _, { get } from "lodash"
import React, { memo, useCallback, useEffect, useRef, useState } from "react"
import isNode from "detect-node"
import { shallowEqual, useDispatch, useSelector } from "react-redux"
import classnames from "classnames"
import { fetchVolunteerNotifsSet } from "../../store/volunteerNotifsSet"
import styles from "./styles.module.scss"
import { selectUserJwtToken } from "../../store/auth"
import { VolunteerNotifs } from "../../services/volunteers"
// import { TeamWishesForm } from ".."
import { fetchFor as fetchForTeamWishesForm } from "../VolunteerBoard/TeamWishesForm/TeamWishesForm"
import TeamWishesForm, {
fetchFor as fetchForTeamWishesForm,
} from "../VolunteerBoard/TeamWishesForm/TeamWishesForm"
import { AppState } from "../../store"
import Block from "../ui/Content/ContentBlock"
import { useUserTeamWishes } from "../VolunteerBoard/teamWishes.utils"
import { useUserDayWishes } from "../VolunteerBoard/daysWishes.utils"
import ParticipationDetailsForm, {
fetchFor as fetchForarticipationDetailsForm,
} from "../VolunteerBoard/ParticipationDetailsForm/ParticipationDetailsForm"
import DayWishesForm, {
fetchFor as fetchForDayWishesForm,
} from "../VolunteerBoard/DayWishesForm/DayWishesForm"
import { useUserParticipationDetails } from "../VolunteerBoard/participationDetails.utils"
import FormButton from "../Form/FormButton/FormButton"
let prevNotifs: VolunteerNotifs | undefined
@ -28,159 +37,123 @@ const Notifications = (): JSX.Element | null => {
const hidden = volunteerNotifs?.hiddenNotifs || []
const notifs: JSX.Element[] = []
const onSubmit1 = useCallback(
(event: React.SyntheticEvent): void => {
event.preventDefault()
const onSubmit1 = useCallback((): void => {
dispatch(
fetchVolunteerNotifsSet(jwtToken, 0, {
hiddenNotifs: [...(volunteerNotifs?.hiddenNotifs || []), 1],
})
)
},
[dispatch, jwtToken, volunteerNotifs]
)
}, [dispatch, jwtToken, volunteerNotifs])
if (!_.includes(hidden, 1)) {
notifs.push(
<div key="1">
<div className={styles.notificationsContent}>
<form onSubmit={onSubmit1}>
<div className={styles.notificationsPage}>
<div className={styles.notificationsContentNarrow}>
<form>
Salut {volunteerNotifs?.firstname} !
<div className={styles.notifIntro} key="login-intro">
Ici tu seras notifié(e) des nouvelles importantes et des questions pour
lesquelles il nous faudrait absolument ta réponse.
Ici tu seras notifié(e) des nouvelles importantes et des questions
pour lesquelles il nous faudrait absolument ta réponse.
<div className={styles.formButtons}>
<button type="submit">Ok, continuer</button>
<FormButton onClick={onSubmit1}>Ok, continuer</FormButton>
</div>
</div>
</form>
</div>
</div>
)
}
const [participation, setParticipation] = useState(volunteerNotifs?.active || "inconnu")
const [participationMessage, setParticipationMessage] = useState("")
const onChangeValue2 = (e: React.ChangeEvent<HTMLInputElement>) =>
setParticipation(e.target.value)
const onSubmit2 = useCallback(
(event: React.SyntheticEvent): void => {
event.preventDefault()
if (participation === "inconnu") {
setParticipationMessage("Il nous faudrait une réponse ^^")
return
}
dispatch(
fetchVolunteerNotifsSet(jwtToken, 0, {
hiddenNotifs: [...(volunteerNotifs?.hiddenNotifs || []), 2],
active: participation,
})
)
},
[dispatch, jwtToken, volunteerNotifs, participation]
)
if (!_.includes(hidden, 2)) {
notifs.push(
<div key="2">
<div className={styles.notificationsContent}>
<div className={styles.formLine} key="line-participation">
<form onSubmit={onSubmit2}>
Si les conditions sanitaires te le permettent, souhaites-tu être
bénévole à PeL 2022 ?<br />
<label>
<input
type="radio"
value="oui"
name="participation"
checked={participation === "oui"}
onChange={onChangeValue2}
/>{" "}
Oui
</label>
<label>
<input
type="radio"
value="non"
name="participation"
checked={participation === "non"}
onChange={onChangeValue2}
/>{" "}
Non
</label>
<label>
<input
type="radio"
value="peut-etre"
name="participation"
checked={participation === "peut-etre"}
onChange={onChangeValue2}
/>{" "}
Je ne sais pas encore
</label>
{participation === "peut-etre" ? (
<div>
On te le reproposera dans quelques temps.
<br />
Si tu as besoin d&apos;infos, viens nous en parler sur le
serveur Discord ! Pour le rejoindre,{" "}
<a
href="https://discord.com/invite/eXhjKxSBB4"
target="_blank"
rel="noreferrer"
>
clique ici{" "}
</a>
.
</div>
) : null}
<div className={styles.formButtons}>
<button type="submit">Confirmer</button>
</div>
<div className={styles.message}>{participationMessage}</div>
</form>
</div>
</div>
</div>
)
}
const onSubmit3 = useCallback((): void => {
dispatch(
fetchVolunteerNotifsSet(jwtToken, 0, {
hiddenNotifs: [...(volunteerNotifs?.hiddenNotifs || []), 3],
})
)
}, [dispatch, jwtToken, volunteerNotifs])
// const [participation, setParticipation] = useState(volunteerNotifs?.active || "inconnu")
// const [participationMessage, setParticipationMessage] = useState("")
// const onChangeValue2 = (e: React.ChangeEvent<HTMLInputElement>) =>
// setParticipation(e.target.value)
if (!_.includes(hidden, 3)) {
notifs.push(
<div key="3">
<div className={styles.notificationsContent}>
<form onSubmit={onSubmit3}>
<div
className={classnames(styles.notifIntro, styles.notifCentered)}
key="login-intro"
>
La{" "}
<a
href="https://mailchi.mp/3c75c3b3a20f/gazette_2020_02-8978118"
onClick={onSubmit3}
>
gazette de février
</a>{" "}
est disponible !<br />
<div className={styles.formButtons}>
<button type="submit">Ok, masquer</button>
</div>
</div>
</form>
</div>
</div>
)
}
// const onSubmit2 = useCallback(
// (): void => {
// if (participation === "inconnu") {
// setParticipationMessage("Il nous faudrait une réponse ^^")
// return
// }
// dispatch(
// fetchVolunteerNotifsSet(jwtToken, 0, {
// hiddenNotifs: [...(volunteerNotifs?.hiddenNotifs || []), 2],
// active: participation,
// })
// )
// },
// [dispatch, jwtToken, volunteerNotifs, participation]
// )
// if (!_.includes(hidden, 2)) {
// notifs.push(
// <div key="2">
// <div className={styles.notificationsPage}>
// <div className={styles.notificationsContentNarrow}>
// <div className={styles.formLine} key="line-participation">
// <form>
// Si les conditions sanitaires te le permettent, souhaites-tu être
// bénévole à PeL 2022 ?<br />
// <label>
// <input
// type="radio"
// value="oui"
// name="participation"
// checked={participation === "oui"}
// onChange={onChangeValue2}
// />{" "}
// Oui
// </label>
// <label>
// <input
// type="radio"
// value="non"
// name="participation"
// checked={participation === "non"}
// onChange={onChangeValue2}
// />{" "}
// Non
// </label>
// <label>
// <input
// type="radio"
// value="peut-etre"
// name="participation"
// checked={participation === "peut-etre"}
// onChange={onChangeValue2}
// />{" "}
// Je ne sais pas encore
// </label>
// {participation === "peut-etre" ? (
// <div>
// On te le reproposera dans quelques temps.
// <br />
// Si tu as besoin d&apos;infos, viens nous en parler sur le
// serveur Discord ! Pour le rejoindre,{" "}
// <a
// href="https://discord.com/invite/eXhjKxSBB4"
// target="_blank"
// rel="noreferrer"
// >
// clique ici{" "}
// </a>
// .
// </div>
// ) : null}
// <div className={styles.formButtons}>
// <FormButton onClick={onSubmit2}>Confirmer</FormButton>
// </div>
// <div className={styles.message}>{participationMessage}</div>
// </form>
// </div>
// </div>
// </div>
// </div>
// )
// }
// const onSubmit3 = useCallback((): void => {
// dispatch(
@ -192,16 +165,121 @@ const Notifications = (): JSX.Element | null => {
// if (!_.includes(hidden, 3)) {
// notifs.push(
// <div key="4">
// <div key="3">
// <div className={styles.notificationsPage}>
// <div className={styles.notificationsContent}>
// <TeamWishesForm afterSubmit={onSubmit3} />
// <div className={styles.notificationsContentNarrow}>
// <form>
// <div
// className={classnames(styles.notifIntro, styles.notifCentered)}
// key="login-intro"
// >
// La{" "}
// <a
// href="https://mailchi.mp/3c75c3b3a20f/gazette_2020_02-8978118"
// onClick={onSubmit3}
// >
// gazette de février
// </a>{" "}
// est disponible !<br />
// <div className={styles.formButtons}>
// <FormButton onClick={onSubmit3}>Ok, masquer</FormButton>
// </div>
// </div>
// </form>
// </div>
// </div>
// </div>
// )
// }
const answerLaterOnProfile = (
<>
Tu pourras y répondre plus tard sur la page <a href="/profil">Mon profil</a>.
</>
)
const onSubmit10 = useCallback((): void => {
dispatch(
fetchVolunteerNotifsSet(jwtToken, 0, {
hiddenNotifs: [...(volunteerNotifs?.hiddenNotifs || []), 10],
})
)
}, [dispatch, jwtToken, volunteerNotifs])
const [userWishes] = useUserDayWishes()
const participation10 = get(userWishes, "active", "inconnu")
const newSelection = get(userWishes, "dayWishes", [])
const comment10 = get(userWishes, "dayWishesComment", "")
const needToShow10 = participation10 === "inconnu" || (newSelection.length === 0 && !comment10)
if (!_.includes(hidden, 10) && needToShow10) {
notifs.push(
<div key="10">
<div className={styles.notificationsPage}>
<div className={styles.notificationsContent}>
<DayWishesForm afterSubmit={onSubmit10}>
{answerLaterOnProfile}
</DayWishesForm>
</div>
</div>
</div>
)
}
const onSubmit11 = useCallback((): void => {
dispatch(
fetchVolunteerNotifsSet(jwtToken, 0, {
hiddenNotifs: [...(volunteerNotifs?.hiddenNotifs || []), 11],
})
)
}, [dispatch, jwtToken, volunteerNotifs])
const [teamWishesData] = useUserTeamWishes()
const teamWishesString = get(teamWishesData, "teamWishes", [])
const comment = get(teamWishesData, "teamWishesComment", "")
const needToShow11 = teamWishesString.length === 0 && !comment
if (!_.includes(hidden, 11) && needToShow11) {
notifs.push(
<div key="11">
<div className={styles.notificationsPage}>
<div className={styles.notificationsContent}>
<TeamWishesForm afterSubmit={onSubmit11}>
{answerLaterOnProfile}
</TeamWishesForm>
</div>
</div>
</div>
)
}
const onSubmit12 = useCallback((): void => {
dispatch(
fetchVolunteerNotifsSet(jwtToken, 0, {
hiddenNotifs: [...(volunteerNotifs?.hiddenNotifs || []), 12],
})
)
}, [dispatch, jwtToken, volunteerNotifs])
const [participationDetails] = useUserParticipationDetails()
const tshirtSize = get(participationDetails, "tshirtSize", "")
const food = get(participationDetails, "food", "")
const needToShow12 = !tshirtSize && !food
if (!_.includes(hidden, 12) && needToShow12) {
notifs.push(
<div key="12">
<div className={styles.notificationsPage}>
<div className={styles.notificationsContent}>
<ParticipationDetailsForm afterSubmit={onSubmit12}>
{answerLaterOnProfile}
</ParticipationDetailsForm>
</div>
</div>
</div>
)
}
/* DISCORD
Discord nous donne à tous la parole via nos téléphone ou navigateurs, pour organiser le meilleur des festivals !
Il permet de discuter sujet par sujet entre tous les bénévoles, entre les membres d'une même équipe, ou avec ton référent.
@ -382,15 +460,16 @@ Tu n'y es absolument pas obligé(e) ! C'est juste plus pratique.
if (notifs.length === 0) {
notifs.push(
<div key="pushNotifs">
<Block title="Notifications">
<div className={styles.notificationsPage}>
<div className={styles.notificationsContent}>
<div className={styles.formLine} key="line-participation">
<label>
Tu as fait le tour des dernières infos ou questions importantes, merci !
:)
Tu as fait le tour des dernières infos ou questions importantes,
merci ! :)
<br />
<br />
Acceptes-tu de recevoir une alerte dans ton navigateur quand on en aura
d&apos;autres spécifiquement pour toi ?<br />
Acceptes-tu de recevoir une alerte dans ton navigateur quand on en
aura d&apos;autres à t'afficher ici ?<br />
<span className={styles.sousMessage}>
(Ça nous simplifierait la vie, on a des soucis à contacter les
bénévoles par email.)
@ -418,11 +497,12 @@ Tu n'y es absolument pas obligé(e) ! C'est juste plus pratique.
</label>
<div className={styles.message}>{notifMessage}</div>
<span className={styles.sousMessage}>
Pas besoin de valider, le site mémorise automatiquement si tu changes ta
réponse.
Pas besoin de valider, le site mémorise automatiquement si tu
changes ta réponse.
</span>
</div>
</Block>
</div>
</div>
</div>
)
}
@ -437,4 +517,8 @@ Tu n'y es absolument pas obligé(e) ! C'est juste plus pratique.
export default memo(Notifications)
// Fetch server-side data here
export const fetchFor = [...fetchForTeamWishesForm]
export const fetchFor = [
...fetchForTeamWishesForm,
...fetchForarticipationDetailsForm,
...fetchForDayWishesForm,
]

View File

@ -6,7 +6,11 @@
}
.notificationsContent {
@include inner-content-wrapper;
@include page-content-wrapper;
}
.notificationsContentNarrow {
@include page-content-wrapper(520px);
}
.pushNotificationsPage {
@ -14,7 +18,7 @@
}
.pushNotificationsContent {
@include inner-content-wrapper;
@include page-content-wrapper;
}
.notifIntro {

View File

@ -6,11 +6,10 @@ import ParticipationDetailsFormModal from "./ParticipationDetailsForm/Participat
import TeamWishes from "./TeamWishes/TeamWishes"
import TeamWishesFormModal from "./TeamWishesForm/TeamWishesFormModal"
import withUserConnected from "../../utils/withUserConnected"
import { fetchVolunteerDayWishesSetIfNeed } from "../../store/volunteerDayWishesSet"
import { fetchVolunteerParticipationDetailsSetIfNeed } from "../../store/volunteerParticipationDetailsSet"
import { fetchTeamListIfNeed } from "../../store/teamList"
import { fetchVolunteerTeamWishesSetIfNeed } from "../../store/volunteerTeamWishesSet"
import ContentTitle from "../ui/Content/ContentTitle"
import { fetchFor as fetchForDayWishesForm } from "./DayWishesForm/DayWishesForm"
import { fetchFor as fetchForParticipationDetailsForm } from "./ParticipationDetailsForm/ParticipationDetailsForm"
import { fetchFor as fetchForTeamWishesForm } from "./TeamWishesForm/TeamWishesForm"
const Board: FC = (): JSX.Element => (
<>
@ -27,8 +26,7 @@ const Board: FC = (): JSX.Element => (
export default memo(withUserConnected(Board))
export const fetchFor = [
fetchVolunteerDayWishesSetIfNeed,
fetchVolunteerParticipationDetailsSetIfNeed,
fetchTeamListIfNeed,
fetchVolunteerTeamWishesSetIfNeed,
...fetchForDayWishesForm,
...fetchForParticipationDetailsForm,
...fetchForTeamWishesForm,
]

View File

@ -32,16 +32,17 @@ const DayWishes: FC = (): JSX.Element | null => {
</div>
)}
{participation === "inconnu" && (
<div className={styles.lineEmpty}>Participation à PeL 2022 non renseignée</div>
<div className={styles.lineEmpty}>
Participation à PeL 2022{" "}
<span className={styles.lineEmpty}>non renseignées</span>
</div>
)}
{participation !== "non" && (
<div className={styles.daysLine}>
<span className={styles.dayLineTitle}>Mes jours :</span>
{dayWishesString && <b>{dayWishesString}</b>}
{!dayWishesString && (
<span className={styles.dayLineEmpty}>Non renseignés</span>
)}
{!dayWishesString && <span className={styles.lineEmpty}>Non renseignés</span>}
</div>
)}
{comment && (

View File

@ -36,7 +36,6 @@
}
.lineEmpty {
margin: 0 5px 5px 0;
color: $color-red;
font-style: italic;
}

View File

@ -1,4 +1,4 @@
import { FC, memo, useCallback, useEffect, useRef, useState } from "react"
import { FC, memo, ReactNode, useCallback, useEffect, useRef, useState } from "react"
import classnames from "classnames"
import get from "lodash/get"
import set from "lodash/set"
@ -10,12 +10,15 @@ import {
useUserDayWishes,
} from "../daysWishes.utils"
import FormButton from "../../Form/FormButton/FormButton"
import { fetchVolunteerDayWishesSetIfNeed } from "../../../store/volunteerDayWishesSet"
import IgnoreButton from "../../Form/IgnoreButton/IgnoreButton"
type Props = {
children?: ReactNode | undefined
afterSubmit?: () => void | undefined
}
const DayWishesForm: FC<Props> = ({ afterSubmit }): JSX.Element => {
const DayWishesForm: FC<Props> = ({ children, afterSubmit }): JSX.Element => {
const [participationState, setParticipation] = useState("inconnu")
const [selection, setSelection] = useState(daysChoiceSelectionDefaultState)
const commentRef = useRef<HTMLTextAreaElement | null>(null)
@ -145,18 +148,35 @@ const DayWishesForm: FC<Props> = ({ afterSubmit }): JSX.Element => {
<label htmlFor="day-choice-comment">Un commentaire, une précision ?</label>
<textarea id="day-choice-comment" ref={commentRef} />
</div>
<div className={styles.dayWishesButtonWrapper}>
<FormButton onClick={onChoiceSubmit}>Enregistrer</FormButton>{" "}
<div className={styles.buttonWrapper}>
<FormButton onClick={onChoiceSubmit}>Enregistrer</FormButton>
{children === undefined && (
<>
{" "}
<FormButton onClick={afterSubmit} type="grey">
Annuler
</FormButton>
</FormButton>{" "}
</>
)}
{children !== undefined && (
<>
{" "}
<IgnoreButton onClick={afterSubmit} text="Ignorer">
{children}
</IgnoreButton>{" "}
</>
)}
</div>
</div>
)
}
DayWishesForm.defaultProps = {
children: undefined,
afterSubmit: undefined,
}
export default memo(DayWishesForm)
// Fetch server-side data here
export const fetchFor = [fetchVolunteerDayWishesSetIfNeed]

View File

@ -24,6 +24,7 @@
}
.rightCol {
width: 100%;
text-align: center;
}
@ -37,7 +38,7 @@
text-align: left;
display: inline-block;
margin-bottom: 10px;
width: 180px;
width: 280px;
}
.dayWishesTitle {
@ -93,7 +94,7 @@
}
}
.dayWishesButtonWrapper {
.buttonWrapper {
margin-bottom: 10px;
text-align: center;
}

View File

@ -26,12 +26,30 @@ const ParticipationDetails: FC<Props> = (): JSX.Element | null => {
<div className={styles.title}>Mes infos logistiques</div>
{tshirtCount === 0 && (
<div className={styles.line}>
Je n'ai <b>aucun t-shirt</b> et je suis taillé·e <b>{tshirtSize}</b>
Je n'ai <b>aucun t-shirt</b> et{" "}
{tshirtSize ? (
<>
je suis taillé·e <b>{tshirtSize}</b>
</>
) : (
<>
ma taille est <span className={styles.lineEmpty}>non renseignées</span>
</>
)}
</div>
)}
{tshirtCount === 1 && (
<div className={styles.line}>
J'ai <b>un seul t-shirt</b> et je suis taillé·e <b>{tshirtSize}</b>
J'ai <b>un seul t-shirt</b> et{" "}
{tshirtSize ? (
<>
je suis taillé·e <b>{tshirtSize}</b>
</>
) : (
<>
ma taille est <span className={styles.lineEmpty}>non renseignées</span>
</>
)}
</div>
)}
{tshirtCount === 2 && (

View File

@ -17,6 +17,11 @@
margin-bottom: 5px;
}
.lineEmpty {
color: $color-red;
font-style: italic;
}
.editButton {
@include vertical-center();

View File

@ -1,19 +1,18 @@
import { FC, memo, useCallback, useEffect, useRef, useState } from "react"
import { FC, memo, ReactNode, useCallback, useEffect, useRef, useState } from "react"
import get from "lodash/get"
import set from "lodash/set"
import styles from "./styles.module.scss"
import {
foodDefaultValue,
tshirtSizes,
useUserParticipationDetails,
} from "../participationDetails.utils"
import { tshirtSizes, useUserParticipationDetails } from "../participationDetails.utils"
import FormButton from "../../Form/FormButton/FormButton"
import { fetchVolunteerParticipationDetailsSetIfNeed } from "../../../store/volunteerParticipationDetailsSet"
import IgnoreButton from "../../Form/IgnoreButton/IgnoreButton"
type Props = {
children?: ReactNode | undefined
afterSubmit?: () => void | undefined
}
const ParticipationDetailsForm: FC<Props> = ({ afterSubmit }): JSX.Element | null => {
const ParticipationDetailsForm: FC<Props> = ({ children, afterSubmit }): JSX.Element | null => {
const sizeRef = useRef<HTMLSelectElement | null>(null)
const dietRef = useRef<HTMLTextAreaElement | null>(null)
const [tshirtCountState, setTshirtCount] = useState<number>(0)
@ -23,7 +22,7 @@ const ParticipationDetailsForm: FC<Props> = ({ afterSubmit }): JSX.Element | nul
const onSubmit = useCallback(() => {
const tshirtSize = get(sizeRef, "current.value", "")
const food = get(dietRef, "current.value", "") || foodDefaultValue
const food = get(dietRef, "current.value", "")
saveParticipationDetails({
tshirtSize,
tshirtCount: tshirtCountState,
@ -103,6 +102,7 @@ const ParticipationDetailsForm: FC<Props> = ({ afterSubmit }): JSX.Element | nul
</label>
</div>
<div className={styles.rightCol}>
<label className={styles.tshirtSizeLabel}>
<select id="tshirtSize" ref={sizeRef} className={styles.tshirtCountSelect}>
{tshirtSizes.map((size) => (
<option key={size} value={size}>
@ -110,6 +110,7 @@ const ParticipationDetailsForm: FC<Props> = ({ afterSubmit }): JSX.Element | nul
</option>
))}
</select>
</label>
</div>
</div>
@ -143,17 +144,34 @@ const ParticipationDetailsForm: FC<Props> = ({ afterSubmit }): JSX.Element | nul
<textarea id="diet" ref={dietRef} placeholder="végétarien ? halal ? ..." />
</div>
<div className={styles.buttonWrapper}>
<FormButton onClick={onSubmit}>Enregistrer</FormButton>{" "}
<FormButton onClick={onSubmit}>Enregistrer</FormButton>
{children === undefined && (
<>
{" "}
<FormButton onClick={afterSubmit} type="grey">
Annuler
</FormButton>
</FormButton>{" "}
</>
)}
{children !== undefined && (
<>
{" "}
<IgnoreButton onClick={afterSubmit} text="Ignorer">
{children}
</IgnoreButton>{" "}
</>
)}
</div>
</div>
)
}
ParticipationDetailsForm.defaultProps = {
children: undefined,
afterSubmit: undefined,
}
export default memo(ParticipationDetailsForm)
// Fetch server-side data here
export const fetchFor = [fetchVolunteerParticipationDetailsSetIfNeed]

View File

@ -27,6 +27,7 @@
}
.rightCol {
width: 100%;
text-align: center;
}
@ -42,13 +43,17 @@
text-align: left;
display: inline-block;
margin-bottom: 10px;
width: 180px;
width: 220px;
}
.tshirtCountSelect {
width: 120px;
.tshirtSizeLabel {
text-align: left;
display: inline-block;
margin-bottom: 10px;
margin-right: 60px;
width: 220px;
}
.tshirtSizeSelect {
border: 1px solid $color-grey-medium;
border-radius: 4px;
background-color: $color-white;
@ -59,12 +64,7 @@
text-align: left;
display: inline-block;
margin-bottom: 10px;
width: 180px;
}
.buttonWrapper {
margin-bottom: 10px;
text-align: center;
width: 220px;
}
.dietWrapper {
@ -83,3 +83,8 @@
outline: 0;
}
}
.buttonWrapper {
margin-bottom: 10px;
text-align: center;
}

View File

@ -1,4 +1,4 @@
import { FC, memo, useCallback, useEffect, useRef } from "react"
import { FC, memo, ReactNode, useCallback, useEffect, useRef } from "react"
import { useSelector } from "react-redux"
import get from "lodash/get"
import set from "lodash/set"
@ -9,12 +9,14 @@ import { fetchTeamListIfNeed, selectSortedActiveTeams } from "../../../store/tea
import useSelection from "../useSelection"
import { fetchVolunteerTeamWishesSetIfNeed } from "../../../store/volunteerTeamWishesSet"
import FormButton from "../../Form/FormButton/FormButton"
import IgnoreButton from "../../Form/IgnoreButton/IgnoreButton"
type Props = {
children?: ReactNode | undefined
afterSubmit?: () => void | undefined
}
const TeamWishesForm: FC<Props> = ({ afterSubmit }): JSX.Element | null => {
const TeamWishesForm: FC<Props> = ({ children, afterSubmit }): JSX.Element | null => {
const teams = useSelector(selectSortedActiveTeams)
const { selection, setSelection, toggleToSelection, isInSelection } = useSelection()
const commentRef = useRef<HTMLTextAreaElement | null>(null)
@ -35,7 +37,7 @@ const TeamWishesForm: FC<Props> = ({ afterSubmit }): JSX.Element | null => {
}, [selection, saveWishes, afterSubmit])
return (
<div className={styles.root}>
<div>
<div className={styles.title}>Mon choix d'équipe</div>
<div className={styles.intro}>
<p>
@ -73,7 +75,7 @@ const TeamWishesForm: FC<Props> = ({ afterSubmit }): JSX.Element | null => {
<textarea id="day-choice-comment" ref={commentRef} />
</div>
</div>
<div>
<div className={styles.rightCol}>
<ul className={styles.teamList}>
{teams.map((team: any) => (
<li
@ -96,16 +98,30 @@ const TeamWishesForm: FC<Props> = ({ afterSubmit }): JSX.Element | null => {
</div>
</div>
<div className={styles.buttonWrapper}>
<FormButton onClick={onSubmit}>Enregistrer</FormButton>{" "}
<FormButton onClick={onSubmit}>Enregistrer</FormButton>
{children === undefined && (
<>
{" "}
<FormButton onClick={afterSubmit} type="grey">
Annuler
</FormButton>
</FormButton>{" "}
</>
)}
{children !== undefined && (
<>
{" "}
<IgnoreButton onClick={afterSubmit} text="Ignorer">
{children}
</IgnoreButton>{" "}
</>
)}
</div>
</div>
)
}
TeamWishesForm.defaultProps = {
children: undefined,
afterSubmit: undefined,
}

View File

@ -1,12 +1,6 @@
@import "../../../theme/variables";
@import "../../../theme/mixins";
.root {
@include desktop {
width: 680px;
}
}
.title {
padding: 4px;
font-weight: bold;
@ -31,10 +25,15 @@
}
.leftCol {
flex: 0 0 280px;
flex: 0 0 240px;
margin-right: 20px;
}
.rightCol {
width: 280px;
text-align: center;
}
.choiceList {
margin: 5px 0 15px;
padding: 0 0 0 30px;
@ -95,7 +94,7 @@
}
textarea {
width: 100%;
height: 50px;
height: 60px;
padding: 5px;
border: 1px solid $color-grey-light;
background-color: $color-grey-lighter;

View File

@ -1,9 +1,16 @@
import AnnouncementLink from "./AnnouncementLink"
import Board, { fetchFor as fetchForBoard } from "./VolunteerBoard/Board"
import DayWishesForm, {
fetchFor as fetchForDayWishesForm,
} from "./VolunteerBoard/DayWishesForm/DayWishesForm"
import ErrorBoundary from "./ErrorBoundary"
import GameList from "./GameList"
import Loading from "./Loading"
import LoginForm from "./LoginForm"
import Notifications, { fetchFor as fetchForNotifications } from "./Notifications"
import ParticipationDetailsForm, {
fetchFor as fetchForParticipationDetailsForm,
} from "./VolunteerBoard/ParticipationDetailsForm/ParticipationDetailsForm"
import PreRegisterForm from "./PreRegisterForm"
import TeamWishesForm, {
fetchFor as fetchForTeamWishesForm,
@ -12,16 +19,21 @@ import VolunteerList from "./VolunteerList"
import VolunteerInfo from "./VolunteerInfo"
import VolunteerSet from "./VolunteerSet"
import WishAdd from "./WishAdd"
import { fetchFor as fetchForBoardForms } from "./VolunteerBoard/Board"
export {
AnnouncementLink,
Board,
fetchForBoard,
DayWishesForm,
fetchForDayWishesForm,
ErrorBoundary,
GameList,
Loading,
LoginForm,
Notifications,
fetchForNotifications,
ParticipationDetailsForm,
fetchForParticipationDetailsForm,
PreRegisterForm,
TeamWishesForm,
fetchForTeamWishesForm,
@ -29,5 +41,4 @@ export {
VolunteerList,
VolunteerSet,
WishAdd,
fetchForBoardForms,
}

View File

@ -5,10 +5,7 @@ import { useSelector } from "react-redux"
import { AppThunk } from "../../store"
import { selectUserJwtToken } from "../../store/auth"
import Page from "../../components/ui/Page/Page"
import Board from "../../components/VolunteerBoard/Board"
import { fetchVolunteerDayWishesSetIfNeed } from "../../store/volunteerDayWishesSet"
import { fetchVolunteerParticipationDetailsSetIfNeed } from "../../store/volunteerParticipationDetailsSet"
import { fetchForTeamWishesForm } from "../../components"
import { Board, fetchForBoard } from "../../components"
export type Props = RouteComponentProps
@ -27,10 +24,6 @@ const BoardPage: FC<Props> = (): JSX.Element => {
}
// Fetch server-side data here
export const loadData = (): AppThunk[] => [
fetchVolunteerDayWishesSetIfNeed(),
fetchVolunteerParticipationDetailsSetIfNeed(),
...fetchForTeamWishesForm.map((f) => f()),
]
export const loadData = (): AppThunk[] => [...fetchForBoard.map((f) => f())]
export default memo(BoardPage)

View File

@ -4,11 +4,10 @@ import { useSelector } from "react-redux"
import { Helmet } from "react-helmet"
import { AppThunk } from "../../store"
import { LoginForm, Notifications, fetchForBoardForms } from "../../components"
import { fetchForNotifications, LoginForm, Notifications } from "../../components"
import styles from "./styles.module.scss"
import { fetchVolunteerNotifsSetIfNeed } from "../../store/volunteerNotifsSet"
import { selectUserJwtToken } from "../../store/auth"
import Page from "../../components/ui/Page/Page"
export type Props = RouteComponentProps
@ -18,11 +17,7 @@ const HomePage: FC<Props> = (): JSX.Element => {
if (jwtToken === undefined) return <p>Loading...</p>
if (jwtToken) {
return (
<Page>
<Notifications />
</Page>
)
return <Notifications />
}
return (
<div>
@ -44,7 +39,7 @@ const HomePage: FC<Props> = (): JSX.Element => {
// Fetch server-side data here
export const loadData = (): AppThunk[] => [
fetchVolunteerNotifsSetIfNeed(),
...fetchForBoardForms.map((f) => f()),
...fetchForNotifications.map((f) => f()),
]
export default memo(HomePage)

View File

@ -22,8 +22,8 @@
@include flex-center;
}
@mixin page-content-wrapper($desktopWidth: 520px) {
margin: 10px;
@mixin page-content-wrapper($desktopWidth: 720px) {
margin: 10px 0;
padding: 10px;
background-color: $color-white;
border-radius: 15px;
@ -31,6 +31,7 @@
width: 100%;
@include desktop {
margin: 10px;
padding: 20px;
width: $desktopWidth;
}
@ -43,7 +44,7 @@
background-color: $color-grey-lighter;
}
@mixin nav-menu($desktopWidth: 520px) {
@mixin nav-menu($desktopWidth: 720px) {
margin: 0;
padding: 0;
list-style: none;
@ -53,7 +54,7 @@
}
}
@mixin nav-menu-item($desktopWidth: 520px) {
@mixin nav-menu-item($desktopWidth: 720px) {
display: inline-block;
margin: 0 4px;