Move Board in /profil, change age by adult, split teeshirt into tshirtSize and tshirtCount

This commit is contained in:
pikiou 2022-03-17 14:28:25 +01:00
parent 850d5e9da6
commit ce13e0c8b4
13 changed files with 215 additions and 127 deletions

View File

@ -24,6 +24,7 @@
@include desktop { @include desktop {
@include horizontal-vertical-center(); @include horizontal-vertical-center();
bottom: auto; bottom: auto;
right: auto; right: auto;
max-height: 80vh; max-height: 80vh;

View File

@ -24,15 +24,15 @@ const MainMenu: FC = (): JSX.Element | null => {
</button> </button>
<ul className={classnames(styles.mainMenu, opened && styles.opened)}> <ul className={classnames(styles.mainMenu, opened && styles.opened)}>
{/* <li className={styles.mainMenuItem}>
<a href="/">Mon espace</a>
</li> */}
<li className={styles.mainMenuItem}>
<a href="/equipes">Equipes</a>
</li>
<li className={styles.mainMenuItem}> <li className={styles.mainMenuItem}>
<a href="/annonces">Annonces</a> <a href="/annonces">Annonces</a>
</li> </li>
<li className={styles.mainMenuItem}>
<a href="/profil">Mon profil</a>
</li>
<li className={styles.mainMenuItem}>
<a href="/equipes">Equipes</a>
</li>
<button type="button" className={styles.close} onClick={onClose}> <button type="button" className={styles.close} onClick={onClose}>
× ×
</button> </button>

View File

@ -47,6 +47,8 @@
display: none; display: none;
@include mobile { @include mobile {
@include vertical-center();
display: block; display: block;
position: absolute; position: absolute;
right: 10px; right: 10px;
@ -55,8 +57,6 @@
text-align: center; text-align: center;
font-size: 22px; font-size: 22px;
color: $color-black; color: $color-black;
@include vertical-center();
} }
} }

View File

@ -11,9 +11,11 @@ import { fetchVolunteerParticipationDetailsSetIfNeed } from "../../store/volunte
import { fetchTeamListIfNeed } from "../../store/teamList" import { fetchTeamListIfNeed } from "../../store/teamList"
import { fetchVolunteerTeamWishesSetIfNeed } from "../../store/volunteerTeamWishesSet" import { fetchVolunteerTeamWishesSetIfNeed } from "../../store/volunteerTeamWishesSet"
import ContentTitle from "../ui/Content/ContentTitle" import ContentTitle from "../ui/Content/ContentTitle"
import VolunteerConfirmation from "../VolunteerConfirmation/VolunteerConfirmation"
const Board: FC = (): JSX.Element => ( const Board: FC = (): JSX.Element => (
<> <>
<VolunteerConfirmation />
<ContentTitle title="Pour le jour J" /> <ContentTitle title="Pour le jour J" />
<DayWishes /> <DayWishes />
<DayWishesFormModal /> <DayWishesFormModal />

View File

@ -11,8 +11,9 @@ type Props = {
const ParticipationDetails: FC<Props> = (): JSX.Element | null => { const ParticipationDetails: FC<Props> = (): JSX.Element | null => {
const [participationDetails] = useUserParticipationDetails() const [participationDetails] = useUserParticipationDetails()
const age = get(participationDetails, "age", "") const adult = get(participationDetails, "adult", "")
const tShirtSize = get(participationDetails, "teeshirtSize", "") const tshirtSize = get(participationDetails, "tshirtSize", "")
const tshirtCount = get(participationDetails, "tshirtCount", "")
const food = get(participationDetails, "food", "") const food = get(participationDetails, "food", "")
const execDisplayModal = useAction(displayModal) const execDisplayModal = useAction(displayModal)
const onEdit = useCallback( const onEdit = useCallback(
@ -23,15 +24,31 @@ const ParticipationDetails: FC<Props> = (): JSX.Element | null => {
return ( return (
<div className={styles.root}> <div className={styles.root}>
<div className={styles.title}>Mes informations pour le festival</div> <div className={styles.title}>Mes informations pour le festival</div>
{!tShirtSize && <div className={styles.line}>J'ai déjà 2 t-shirts.</div>} {tshirtCount === 0 && (
{tShirtSize && (
<div className={styles.line}> <div className={styles.line}>
J'ai besoin d'un t-shirt ! (Taille <b>{tShirtSize}</b>) Je n'ai <b>aucun t-shirt</b>. (Taille <b>{tshirtSize}</b>)
</div> </div>
)} )}
{tshirtCount === 1 && (
<div className={styles.line}> <div className={styles.line}>
Age : <b>{age || "?"} ans</b>. J'ai déjà <b>1 t-shirt</b>. (Taille <b>{tshirtSize}</b>)
</div> </div>
)}
{tshirtCount === 2 && (
<div className={styles.line}>
J'ai déjà <b>2 t-shirts</b>.
</div>
)}
{adult === 0 && (
<div className={styles.line}>
Je suis <b>mineur</b>
</div>
)}
{adult === 1 && (
<div className={styles.line}>
Je suis <b>majeur</b>
</div>
)}
<div className={styles.line}> <div className={styles.line}>
Préférence alimentaire : <b>{food || foodDefaultValue}</b> Préférence alimentaire : <b>{food || foodDefaultValue}</b>
</div> </div>

View File

@ -4,7 +4,7 @@ import set from "lodash/set"
import styles from "./styles.module.scss" import styles from "./styles.module.scss"
import { import {
foodDefaultValue, foodDefaultValue,
tShirtSizes, tshirtSizes,
useUserParticipationDetails, useUserParticipationDetails,
} from "../participationDetails.utils" } from "../participationDetails.utils"
import FormButton from "../../Form/FormButton/FormButton" import FormButton from "../../Form/FormButton/FormButton"
@ -16,79 +16,131 @@ type Props = {
const ParticipationDetailsForm: FC<Props> = ({ afterSubmit }): JSX.Element | null => { const ParticipationDetailsForm: FC<Props> = ({ afterSubmit }): JSX.Element | null => {
const sizeRef = useRef<HTMLSelectElement | null>(null) const sizeRef = useRef<HTMLSelectElement | null>(null)
const dietRef = useRef<HTMLInputElement | null>(null) const dietRef = useRef<HTMLInputElement | null>(null)
const ageRef = useRef<HTMLInputElement | null>(null) const [tshirtCountState, setTshirtCount] = useState<number>(0)
const [has2Shirts, setHas2Shirts] = useState<boolean>(true) const [adultState, setAdult] = useState<number>(0)
const [participationDetails, saveParticipationDetails] = useUserParticipationDetails() const [participationDetails, saveParticipationDetails] = useUserParticipationDetails()
const onSubmit = useCallback(() => { const onSubmit = useCallback(() => {
const age = get(ageRef, "current.value", "") const tshirtSize = get(sizeRef, "current.value", "")
const teeshirtSize = has2Shirts ? "" : get(sizeRef, "current.value", "")
const food = get(dietRef, "current.value", "") || foodDefaultValue const food = get(dietRef, "current.value", "") || foodDefaultValue
saveParticipationDetails({ age, teeshirtSize, food }) saveParticipationDetails({
tshirtSize,
tshirtCount: tshirtCountState,
adult: adultState,
food,
})
if (afterSubmit) afterSubmit() if (afterSubmit) afterSubmit()
}, [has2Shirts, saveParticipationDetails, afterSubmit]) }, [tshirtCountState, adultState, saveParticipationDetails, afterSubmit])
const onHas2ShirtsClick = useCallback( const onTshirtCountChange = useCallback(
(value) => { (value) => {
setHas2Shirts(value) setTshirtCount(value)
}, },
[setHas2Shirts] [setTshirtCount]
)
const onAdultChange = useCallback(
(value) => {
setAdult(value)
},
[setAdult]
) )
useEffect(() => { useEffect(() => {
const age = get(participationDetails, "age", "") const tshirtSize = get(participationDetails, "tshirtSize", "")
const teeshirtSize = get(participationDetails, "teeshirtSize", "") const tshirtCount = get(participationDetails, "tshirtCount", "")
const adult = get(participationDetails, "adult", "")
const food = get(participationDetails, "food", "") const food = get(participationDetails, "food", "")
if (age) set(ageRef, "current.value", age) if (tshirtSize) set(sizeRef, "current.value", tshirtSize)
if (teeshirtSize) set(sizeRef, "current.value", teeshirtSize) if (tshirtCount) setTshirtCount(tshirtCount)
setHas2Shirts(!teeshirtSize) if (adult) setAdult(adult)
if (food) set(dietRef, "current.value", food) if (food) set(dietRef, "current.value", food)
}, [setHas2Shirts, participationDetails]) }, [setTshirtCount, setAdult, participationDetails])
return ( return (
<div className={styles.root}> <div>
<div className={styles.title}>Mes informations pour le festival</div> <div className={styles.title}>Mes informations pour le festival</div>
<div className={styles.tShirtWrapper}> <div className={styles.inputWrapper}>
<div className={styles.tShirtLabel}>J'ai déjà 2 t-shirts</div> <div className={styles.leftCol}>
<label> <div className={styles.tshirtCountTitle}>Combien as-tu de t-shirts PeL ?</div>
</div>
<div>
<label className={styles.tshirtCountLabel}>
<input <input
type="radio" type="radio"
name="hasShirt" name="tshirtCount"
onChange={() => onHas2ShirtsClick(true)} onChange={() => onTshirtCountChange(0)}
checked={has2Shirts} checked={tshirtCountState === 0}
/>{" "} />{" "}
Oui 0
</label> </label>
<label> <label className={styles.tshirtCountLabel}>
<input <input
type="radio" type="radio"
name="hasShirt" name="tshirtCount"
onChange={() => onHas2ShirtsClick(false)} onChange={() => onTshirtCountChange(1)}
checked={!has2Shirts} checked={tshirtCountState === 1}
/>{" "} />{" "}
Non 1
</label> </label>
{has2Shirts === false && ( <label className={styles.tshirtCountLabel}>
<div className={styles.tShirtSizes}> <input
<label>Taille</label> type="radio"
<select ref={sizeRef}> name="tshirtCount"
{tShirtSizes.map((size) => ( onChange={() => onTshirtCountChange(2)}
checked={tshirtCountState === 2}
/>{" "}
2 ou plus
</label>
</div>
</div>
<div className={styles.inputWrapper}>
<div className={styles.leftCol}>
<div className={styles.tshirtSizesTitle}>Taille</div>
</div>
<div>
<select ref={sizeRef} className={styles.tshirtCountSelect}>
{tshirtSizes.map((size) => (
<option key={size} value={size}> <option key={size} value={size}>
{size} {size}
</option> </option>
))} ))}
</select> </select>
</div> </div>
)} </div>
</div>
<div className={styles.inputWrapper}> <div className={styles.inputWrapper}>
<label htmlFor="ddday-age">Age</label> <div className={styles.leftCol}>
<input type="number" id="ddday-age" ref={ageRef} /> <div className={styles.adultTitle}>Le 2 juillet 2022 tu auras :</div>
</div>
<div>
<label className={styles.adultLabel}>
<input
type="radio"
name="majority"
onChange={() => onAdultChange(0)}
checked={adultState === 0}
/>{" "}
17 ou moins
</label>
<label className={styles.adultLabel}>
<input
type="radio"
name="majority"
onChange={() => onAdultChange(1)}
checked={adultState === 1}
/>{" "}
18 ans ou plus
</label>
</div>
</div> </div>
<div className={styles.inputWrapper}> <div className={styles.inputWrapper}>
<div className={styles.leftCol}>
<label htmlFor="dday-diet">Préférence alimentaire</label> <label htmlFor="dday-diet">Préférence alimentaire</label>
</div>
<div>
<input <input
id="dday-diet" id="dday-diet"
type="text" type="text"
@ -96,6 +148,7 @@ const ParticipationDetailsForm: FC<Props> = ({ afterSubmit }): JSX.Element | nul
placeholder="végétarien ? halal ? ..." placeholder="végétarien ? halal ? ..."
/> />
</div> </div>
</div>
<div className={styles.buttonWrapper}> <div className={styles.buttonWrapper}>
<FormButton onClick={onSubmit}>Enregistrer</FormButton> <FormButton onClick={onSubmit}>Enregistrer</FormButton>
</div> </div>

View File

@ -1,10 +1,6 @@
@import "../../../theme/variables"; @import "../../../theme/variables";
@import "../../../theme/mixins"; @import "../../../theme/mixins";
.root {
width: 470px;
}
.title { .title {
padding: 4px; padding: 4px;
font-weight: bold; font-weight: bold;
@ -14,46 +10,61 @@
.inputWrapper { .inputWrapper {
margin: 10px 0; margin: 10px 0;
@include desktop {
display: flex;
}
label { label {
display: inline-block; display: block;
width: 170px; width: 170px;
} }
input { input[type="text"] {
width: 300px; min-width: 175px;
border: 1px solid $color-grey-medium; border: 1px solid $color-grey-medium;
outline: 0; outline: 0;
} }
} }
.tShirtWrapper { .leftCol {
flex: 0 0 240px;
}
.tshirtWrapper {
margin: 10px 0; margin: 10px 0;
height: 28px; height: 28px;
label {
display: inline-block;
width: 55px;
}
} }
.tShirtLabel { .tshirtCountTitle {
display: inline-block; display: inline-block;
margin-top: 6px; margin-top: 6px;
width: 170px; width: 240px;
} }
.tShirtSizes { .tshirtCountLabel {
display: inline-block; width: 55px;
width: 190px; }
text-align: right;
select { .tshirtSizesTitle {
margin-left: 10px; display: inline-block;
width: 240px;
}
.tshirtCountSelect {
width: 120px; width: 120px;
border: 1px solid $color-grey-medium; border: 1px solid $color-grey-medium;
border-radius: 4px; border-radius: 4px;
background-color: $color-white; background-color: $color-white;
outline: 0; outline: 0;
} }
.adultTitle {
display: inline-block;
margin-top: 6px;
width: 240px;
}
.adultLabel {
width: 55px;
} }
.buttonWrapper { .buttonWrapper {

View File

@ -42,6 +42,7 @@
.teamList { .teamList {
@include clear-ul-style; @include clear-ul-style;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
flex-direction: row; flex-direction: row;

View File

@ -5,7 +5,7 @@ import { selectUserJwtToken } from "../../store/auth"
import { AppState } from "../../store" import { AppState } from "../../store"
import { fetchVolunteerParticipationDetailsSet } from "../../store/volunteerParticipationDetailsSet" import { fetchVolunteerParticipationDetailsSet } from "../../store/volunteerParticipationDetailsSet"
export const tShirtSizes = [ export const tshirtSizes = [
"XS", "XS",
"S", "S",
"M", "M",
@ -29,12 +29,13 @@ export const useUserParticipationDetails = (): [any, any] => {
) )
const saveParticipationDetails = useCallback( const saveParticipationDetails = useCallback(
({ age, teeshirtSize, food }) => { ({ tshirtSize, tshirtCount, adult, food }) => {
if (!userParticipationDetails) return if (!userParticipationDetails) return
save(jwtToken, 0, { save(jwtToken, 0, {
id: userParticipationDetails.id, id: userParticipationDetails.id,
age, tshirtSize,
teeshirtSize, tshirtCount,
adult,
food, food,
}) })
}, },

View File

@ -6,26 +6,21 @@ import { Helmet } from "react-helmet"
import { AppThunk } from "../../store" import { AppThunk } from "../../store"
import { LoginForm, Notifications, fetchForBoardForms } from "../../components" import { LoginForm, Notifications, fetchForBoardForms } from "../../components"
import styles from "./styles.module.scss" import styles from "./styles.module.scss"
import { fetchVolunteerNotifsSetIfNeed, hasWaitingNotifs } from "../../store/volunteerNotifsSet" import { fetchVolunteerNotifsSetIfNeed } from "../../store/volunteerNotifsSet"
import { selectUserJwtToken } from "../../store/auth" import { selectUserJwtToken } from "../../store/auth"
import Board from "../../components/VolunteerBoard/Board"
import Page from "../../components/ui/Page/Page" import Page from "../../components/ui/Page/Page"
import VolunteerConfirmation from "../../components/VolunteerConfirmation/VolunteerConfirmation"
export type Props = RouteComponentProps export type Props = RouteComponentProps
const HomePage: FC<Props> = (): JSX.Element => { const HomePage: FC<Props> = (): JSX.Element => {
const jwtToken = useSelector(selectUserJwtToken) const jwtToken = useSelector(selectUserJwtToken)
const waitingNotifs = useSelector(hasWaitingNotifs)
if (jwtToken === undefined) return <p>Loading...</p> if (jwtToken === undefined) return <p>Loading...</p>
if (jwtToken) { if (jwtToken) {
return ( return (
<Page> <Page>
{!waitingNotifs && <VolunteerConfirmation />}
<Notifications /> <Notifications />
{!waitingNotifs && <Board />}
</Page> </Page>
) )
} }

View File

@ -57,7 +57,7 @@ export default [
loadData: loadWishData, loadData: loadWishData,
}, },
{ {
path: "/board", path: "/profil",
component: AsyncBoard, component: AsyncBoard,
loadData: loadBoardData, loadData: loadBoardData,
}, },

View File

@ -206,7 +206,9 @@ export const volunteerDayWishesSet = expressAccessor.set(async (list, body, id)
export const volunteerParticipationDetailsSet = expressAccessor.set(async (list, body, id) => { export const volunteerParticipationDetailsSet = expressAccessor.set(async (list, body, id) => {
const requestedId = +body[0] || id const requestedId = +body[0] || id
if (requestedId !== id && requestedId !== 0) { if (requestedId !== id && requestedId !== 0) {
throw Error(`On ne peut acceder qu'à ses propres infos d'age, taille et alimentation`) throw Error(
`On ne peut acceder qu'à ses propres infos de t-shirt, de majorité et d'alimentation`
)
} }
const wishes = body[1] as VolunteerParticipationDetails const wishes = body[1] as VolunteerParticipationDetails
const volunteer = list.find((v) => v.id === requestedId) const volunteer = list.find((v) => v.id === requestedId)
@ -215,11 +217,14 @@ export const volunteerParticipationDetailsSet = expressAccessor.set(async (list,
} }
const newVolunteer = _.cloneDeep(volunteer) const newVolunteer = _.cloneDeep(volunteer)
if (wishes.age !== undefined) { if (wishes.tshirtSize !== undefined) {
newVolunteer.age = wishes.age newVolunteer.tshirtSize = wishes.tshirtSize
} }
if (wishes.teeshirtSize !== undefined) { if (wishes.tshirtCount !== undefined) {
newVolunteer.teeshirtSize = wishes.teeshirtSize newVolunteer.tshirtCount = wishes.tshirtCount
}
if (wishes.adult !== undefined) {
newVolunteer.adult = wishes.adult
} }
if (wishes.food !== undefined) { if (wishes.food !== undefined) {
newVolunteer.food = wishes.food newVolunteer.food = wishes.food
@ -229,8 +234,9 @@ export const volunteerParticipationDetailsSet = expressAccessor.set(async (list,
toDatabase: newVolunteer, toDatabase: newVolunteer,
toCaller: { toCaller: {
id: newVolunteer.id, id: newVolunteer.id,
age: newVolunteer.age, tshirtSize: newVolunteer.tshirtSize,
teeshirtSize: newVolunteer.teeshirtSize, tshirtCount: newVolunteer.tshirtCount,
adult: newVolunteer.adult,
food: newVolunteer.food, food: newVolunteer.food,
} as VolunteerParticipationDetails, } as VolunteerParticipationDetails,
} }

View File

@ -23,9 +23,9 @@ export class Volunteer {
dayWishesComment = "" dayWishesComment = ""
age = 0 tshirtCount = ""
teeshirtSize = "" tshirtSize = ""
food = "" food = ""
@ -59,8 +59,8 @@ export const translationVolunteer: { [k in keyof Volunteer]: string } = {
discordId: "discordId", discordId: "discordId",
dayWishes: "enviesJours", dayWishes: "enviesJours",
dayWishesComment: "commentaireEnviesJours", dayWishesComment: "commentaireEnviesJours",
age: "age", tshirtCount: "nbDeTshirts",
teeshirtSize: "teeshirt", tshirtSize: "tailleDeTshirts",
food: "alimentation", food: "alimentation",
teamWishes: "enviesEquipe", teamWishes: "enviesEquipe",
teamWishesComment: "commentaireEnviesEquipe", teamWishesComment: "commentaireEnviesEquipe",
@ -87,8 +87,8 @@ export const volunteerExample: Volunteer = {
discordId: "", discordId: "",
dayWishes: [], dayWishes: [],
dayWishesComment: "", dayWishesComment: "",
age: 33, tshirtCount: "1",
teeshirtSize: "FM", tshirtSize: "Femme M",
food: "Végétarien", food: "Végétarien",
teamWishes: [], teamWishes: [],
teamWishesComment: "", teamWishesComment: "",
@ -140,7 +140,8 @@ export interface VolunteerDayWishes {
export interface VolunteerParticipationDetails { export interface VolunteerParticipationDetails {
id: Volunteer["id"] id: Volunteer["id"]
age: Volunteer["age"] tshirtSize: Volunteer["tshirtSize"]
teeshirtSize: Volunteer["teeshirtSize"] tshirtCount: Volunteer["tshirtCount"]
adult: Volunteer["adult"]
food: Volunteer["food"] food: Volunteer["food"]
} }