days wishes components

This commit is contained in:
memeriau 2022-01-24 14:26:36 +01:00
parent 6d0134cb63
commit 3fd6741a78
7 changed files with 150 additions and 94 deletions

View File

@ -1,10 +1,31 @@
import { FC, memo, useCallback, useState } from "react"
import { FC, memo, useCallback, useEffect, useRef, useState } from "react"
import classnames from "classnames"
import { daysChoice, daysChoiceSelectionDefaultState } from "./days.utils"
import get from "lodash/get"
import styles from "./styles.module.scss"
import {
daysChoice,
daysChoiceSelectionDefaultState,
selectionChoices,
useUserDayWishes,
} from "./days.utils"
const DayWishes: FC = (): JSX.Element | null => {
const [selection, setSelection] = useState(daysChoiceSelectionDefaultState)
const commentRef = useRef<HTMLTextAreaElement | null>(null)
const [userWishes, saveWishes] = useUserDayWishes()
useEffect(() => {
if (!userWishes) return
const newSelection = get(userWishes, "dayWishes", []).reduce(
(acc: selectionChoices, day: string) => ({
...acc,
[day]: true,
}),
daysChoice
)
setSelection(newSelection)
}, [setSelection, userWishes])
const onChoiceClick = useCallback(
(id) => {
setSelection({
@ -14,24 +35,41 @@ const DayWishes: FC = (): JSX.Element | null => {
},
[selection, setSelection]
)
const onChoiceSubmit = useCallback(() => {
const comment = get(commentRef, "current.value", "")
const days = daysChoice.map(({ id }) => id).filter((id) => selection[id])
saveWishes(days, comment)
}, [selection, commentRef, saveWishes])
return (
<ul className={styles.dayWishes}>
{daysChoice.map(({ id, label }) => (
<li key={id} className={styles.dayWishesItem}>
<button
type="button"
onClick={() => onChoiceClick(id)}
className={classnames(
styles.dayWishesButton,
selection[id] && styles.active
)}
>
{label}
</button>
</li>
))}
</ul>
<div className={styles.dayWishes}>
<div className={styles.dayWishesTitle}>Jours de présence</div>
<ul className={styles.dayWishesList}>
{daysChoice.map(({ id, label }) => (
<li key={id} className={styles.dayWishesItem}>
<button
type="button"
onClick={() => onChoiceClick(id)}
className={classnames(
styles.dayWishesButton,
selection[id] && styles.active
)}
>
{label}
</button>
</li>
))}
</ul>
<div className={styles.dayWishCommentWrapper}>
<label htmlFor="day-choice-comment">Commentaires</label>
<textarea id="day-choice-comment" ref={commentRef} />
</div>
<div className={styles.dayWishesButtonWrapper}>
<button type="submit" onClick={onChoiceSubmit}>
Enregistrer
</button>
</div>
</div>
)
}

View File

@ -1,3 +1,10 @@
import { shallowEqual, useSelector } from "react-redux"
import { useCallback } from "react"
import { selectUserJwtToken } from "../../../store/auth"
import { AppState } from "../../../store"
import { fetchVolunteerDayWishesSet } from "../../../store/volunteerDayWishesSet"
import useAction from "../../../utils/useAction"
const daysUtils = ["Jeudi", "Vendredi", "Samedi", "Dimanche", "Lundi"]
export const daysChoice = daysUtils.map((label) => ({
@ -5,7 +12,7 @@ export const daysChoice = daysUtils.map((label) => ({
label,
}))
interface selectionChoices {
export interface selectionChoices {
[key: string]: boolean
}
@ -13,3 +20,26 @@ export const daysChoiceSelectionDefaultState = daysChoice.reduce((state, { id })
state[id] = false
return state
}, <selectionChoices>{})
export const useUserDayWishes = (): [any, any] => {
const save = useAction(fetchVolunteerDayWishesSet)
const jwtToken = useSelector(selectUserJwtToken)
const userWishes = useSelector(
(state: AppState) => state.volunteerDayWishesSet?.entity,
shallowEqual
)
const saveWishes = useCallback(
(days, comment) => {
if (!userWishes) return
save(jwtToken, 0, {
id: userWishes.id,
dayWishes: days,
dayWishesComment: comment,
})
},
[userWishes, save, jwtToken]
)
return [userWishes, saveWishes]
}

View File

@ -2,6 +2,16 @@
@import "../../../theme/mixins";
.dayWishes {
width: 470px;
}
.dayWishesTitle {
padding: 4px;
font-weight: bold;
text-align: center;
}
.dayWishesList {
@include clear-ul-style;
}
@ -12,7 +22,7 @@
.dayWishesButton {
margin: 0;
padding: 4px;
padding: 5px 0 4px;
border: 0;
border-radius: 0;
width: 90px;
@ -26,3 +36,25 @@
background-color: $color-black;
}
}
.dayWishCommentWrapper {
margin: 6px 0;
label {
display: block;
padding-left: 4px;
}
textarea {
width: 100%;
height: 50px;
padding: 5px;
border: 1px solid $color-grey-light;
background-color: $color-grey-lighter;
outline: 0;
}
}
.dayWishesButtonWrapper {
margin-bottom: 10px;
text-align: center;
}

View File

@ -1,90 +1,25 @@
import { FC, memo, useCallback, useEffect, useState } from "react"
import { FC, memo } from "react"
import { RouteComponentProps } from "react-router-dom"
import { useSelector, shallowEqual, useDispatch } from "react-redux"
import { useSelector } from "react-redux"
import { AppState, AppThunk } from "../../store"
import {
fetchVolunteerDayWishesSet,
fetchVolunteerDayWishesSetIfNeed,
} from "../../store/volunteerDayWishesSet"
import { VolunteerDayWishes } from "../../services/volunteers"
import { AppThunk } from "../../store"
import { fetchVolunteerDayWishesSetIfNeed } from "../../store/volunteerDayWishesSet"
import { selectUserJwtToken } from "../../store/auth"
import DayWishes from "../../components/VolunteerBoard/DayWishes/DayWishes"
import styles from "./styles.module.scss"
export type Props = RouteComponentProps
let prevWishes: VolunteerDayWishes | undefined
const HomePage: FC<Props> = (): JSX.Element => {
const dispatch = useDispatch()
const jwtToken = useSelector(selectUserJwtToken)
const wishesForm = useSelector((state: AppState) => {
const wishes = state.volunteerDayWishesSet?.entity
if (wishes) {
prevWishes = wishes
return wishes
}
return prevWishes
}, shallowEqual)
const [dayWishes, setDayWishes] = useState(wishesForm?.dayWishes.join(",") || "")
const [dayWishesComment, setDayWishesComment] = useState(wishesForm?.dayWishesComment || "")
useEffect(() => {
setDayWishes(wishesForm?.dayWishes.join(",") || "")
setDayWishesComment(wishesForm?.dayWishesComment || "")
}, [wishesForm])
const onDayWishesChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
setDayWishes(e.target.value)
const onDayWishesCommentChanged = (e: React.ChangeEvent<HTMLInputElement>) =>
setDayWishesComment(e.target.value)
const onSubmit = useCallback(
(event: React.SyntheticEvent): void => {
event.preventDefault()
if (!wishesForm) {
console.error("NO FORM WISHES RECEIVED")
return // Form should not even appear if this happens
}
dispatch(
fetchVolunteerDayWishesSet(jwtToken, 0, {
id: wishesForm.id,
dayWishes: (dayWishes || "").split(","),
dayWishesComment,
})
)
},
[dispatch, jwtToken, wishesForm, dayWishes, dayWishesComment]
)
if (jwtToken === undefined) return <p>Loading...</p>
if (jwtToken) {
return (
<div>
<DayWishes />
<form>
<input
type="text"
id="dayWishes"
required
value={dayWishes}
onChange={onDayWishesChanged}
/>
<br />
<input
type="text"
id="dayWishesComment"
required
value={dayWishesComment}
onChange={onDayWishesCommentChanged}
/>
<button type="button" onClick={onSubmit}>
Envoyer
</button>
</form>
<div className={styles.dayWishPage}>
<div className={styles.dayWisContent}>
<DayWishes />
</div>
</div>
)
}

View File

@ -1 +1,9 @@
@import "../../theme/mixins";
.dayWishPage {
@include page-wrapper-center;
}
.dayWisContent {
@include page-content-wrapper(800px);
}

View File

@ -3,7 +3,9 @@ $color-black: #000;
$color-orange: #ea4d0a;
$color-yellow: #fdd137;
$color-grey-dark: #555;
$color-grey-medium: #999;
$color-grey-light: #ccc;
$color-grey-lighter: #eee;
$border-large: 4px solid $color-black;
$border-thin: 2px solid $color-black;

11
src/utils/useAction.ts Normal file
View File

@ -0,0 +1,11 @@
import { useDispatch } from "react-redux"
const useAction = (action: (...args: any[]) => any): any => {
const dispatch = useDispatch()
return (...args: any[]) => {
dispatch(action(...args))
}
}
export default useAction