mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-09 00:54:21 +02:00
add component to display day wishes
This commit is contained in:
parent
bf649aa040
commit
2bfd8d2a7b
@ -1,76 +1,30 @@
|
||||
import { FC, memo, useCallback, useEffect, useRef, useState } from "react"
|
||||
import classnames from "classnames"
|
||||
import { FC, memo } from "react"
|
||||
import get from "lodash/get"
|
||||
import set from "lodash/set"
|
||||
import styles from "./styles.module.scss"
|
||||
import {
|
||||
daysChoice,
|
||||
daysChoiceSelectionDefaultState,
|
||||
selectionChoices,
|
||||
useUserDayWishes,
|
||||
} from "./days.utils"
|
||||
import { getDayLabel, 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
|
||||
console.log("userWishes", userWishes)
|
||||
const newSelection = get(userWishes, "dayWishes", []).reduce(
|
||||
(acc: selectionChoices, day: string) => ({
|
||||
...acc,
|
||||
[day]: true,
|
||||
}),
|
||||
daysChoice
|
||||
)
|
||||
setSelection(newSelection)
|
||||
set(commentRef, "current.value", get(userWishes, "dayWishesComment", ""))
|
||||
}, [setSelection, commentRef, userWishes])
|
||||
|
||||
const onChoiceClick = useCallback(
|
||||
(id) => {
|
||||
setSelection({
|
||||
...selection,
|
||||
[id]: !selection[id],
|
||||
})
|
||||
},
|
||||
[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])
|
||||
const [userWishes] = useUserDayWishes()
|
||||
const dayWishesString = get(userWishes, "dayWishes", []).map(getDayLabel).join(", ")
|
||||
const comment = get(userWishes, "dayWishesComment", "")
|
||||
|
||||
return (
|
||||
<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 className={styles.daysLine}>
|
||||
<span className={styles.dayLineTitle}>Mes jours de présence :</span>
|
||||
{dayWishesString && <span>{dayWishesString}</span>}
|
||||
{!dayWishesString && <span>Non renseignés</span>}
|
||||
</div>
|
||||
<div className={styles.dayWishesButtonWrapper}>
|
||||
<button type="submit" onClick={onChoiceSubmit}>
|
||||
Enregistrer
|
||||
</button>
|
||||
{comment && (
|
||||
<div className={styles.commentLine}>
|
||||
<span className={styles.commentLineTitle}>Mon commentaire :</span>
|
||||
<span className={styles.commentLineText}>
|
||||
{get(userWishes, "dayWishesComment", "")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.editButton}>
|
||||
<button type="button">Modifier</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -2,59 +2,39 @@
|
||||
@import "../../../theme/mixins";
|
||||
|
||||
.dayWishes {
|
||||
width: 470px;
|
||||
@include inner-content-wrapper();
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dayWishesTitle {
|
||||
padding: 4px;
|
||||
.daysLine,
|
||||
.commentLine {
|
||||
span {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.dayLineTitle {
|
||||
padding-right: 5px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dayWishesList {
|
||||
@include clear-ul-style;
|
||||
.dayLineEmpty {
|
||||
color: $color-red;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.dayWishesItem {
|
||||
display: inline-block;
|
||||
margin: 2px;
|
||||
.commentLineTitle {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.dayWishesButton {
|
||||
margin: 0;
|
||||
padding: 5px 0 4px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
width: 90px;
|
||||
text-align: center;
|
||||
color: $color-grey-dark;
|
||||
background-color: $color-grey-light;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
color: $color-yellow;
|
||||
background-color: $color-black;
|
||||
}
|
||||
.commentLineText {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.dayWishCommentWrapper {
|
||||
margin: 6px 0;
|
||||
.editButton {
|
||||
@include vertical-center();
|
||||
|
||||
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;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
import { FC, memo, useCallback, useEffect, useRef, useState } from "react"
|
||||
import classnames from "classnames"
|
||||
import get from "lodash/get"
|
||||
import set from "lodash/set"
|
||||
import styles from "./styles.module.scss"
|
||||
import {
|
||||
daysChoice,
|
||||
daysChoiceSelectionDefaultState,
|
||||
selectionChoices,
|
||||
useUserDayWishes,
|
||||
} from "../days.utils"
|
||||
|
||||
const DayWishesForm: 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)
|
||||
set(commentRef, "current.value", get(userWishes, "dayWishesComment", ""))
|
||||
}, [setSelection, commentRef, userWishes])
|
||||
|
||||
const onChoiceClick = useCallback(
|
||||
(id) => {
|
||||
setSelection({
|
||||
...selection,
|
||||
[id]: !selection[id],
|
||||
})
|
||||
},
|
||||
[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 (
|
||||
<div className={styles.dayWishesForm}>
|
||||
<div className={styles.dayWishesTitle}>Mes 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">Un commentaire, une précision ?</label>
|
||||
<textarea id="day-choice-comment" ref={commentRef} />
|
||||
</div>
|
||||
<div className={styles.dayWishesButtonWrapper}>
|
||||
<button type="submit" onClick={onChoiceSubmit}>
|
||||
Enregistrer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(DayWishesForm)
|
60
src/components/VolunteerBoard/DayWishesForm/styles.module.scss
Executable file
60
src/components/VolunteerBoard/DayWishesForm/styles.module.scss
Executable file
@ -0,0 +1,60 @@
|
||||
@import "../../../theme/variables";
|
||||
@import "../../../theme/mixins";
|
||||
|
||||
.dayWishesForm {
|
||||
width: 470px;
|
||||
}
|
||||
|
||||
.dayWishesTitle {
|
||||
padding: 4px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dayWishesList {
|
||||
@include clear-ul-style;
|
||||
}
|
||||
|
||||
.dayWishesItem {
|
||||
display: inline-block;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.dayWishesButton {
|
||||
margin: 0;
|
||||
padding: 5px 0 4px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
width: 90px;
|
||||
text-align: center;
|
||||
color: $color-grey-dark;
|
||||
background-color: $color-grey-light;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
color: $color-yellow;
|
||||
background-color: $color-black;
|
||||
}
|
||||
}
|
||||
|
||||
.dayWishCommentWrapper {
|
||||
margin: 6px 0;
|
||||
|
||||
label {
|
||||
display: block;
|
||||
padding: 6px 0 2px 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;
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
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"
|
||||
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"]
|
||||
|
||||
@ -43,3 +43,8 @@ export const useUserDayWishes = (): [any, any] => {
|
||||
|
||||
return [userWishes, saveWishes]
|
||||
}
|
||||
|
||||
export const getDayLabel = (id: string): string => {
|
||||
const matchingDay = daysChoice.find((day) => day.id === id)
|
||||
return matchingDay ? matchingDay.label : ""
|
||||
}
|
36
src/pages/Board/Board.tsx
Normal file
36
src/pages/Board/Board.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import { FC, memo } from "react"
|
||||
import { RouteComponentProps } from "react-router-dom"
|
||||
import { useSelector } from "react-redux"
|
||||
|
||||
import { AppThunk } from "../../store"
|
||||
import { fetchVolunteerDayWishesSetIfNeed } from "../../store/volunteerDayWishesSet"
|
||||
import { selectUserJwtToken } from "../../store/auth"
|
||||
import DayWishesForm from "../../components/VolunteerBoard/DayWishesForm/DayWishesForm"
|
||||
import DDayInformations from "../../components/VolunteerBoard/DDayInformations/DDaysInformations"
|
||||
import styles from "./styles.module.scss"
|
||||
import DayWishes from "../../components/VolunteerBoard/DayWishes/DayWishes"
|
||||
|
||||
export type Props = RouteComponentProps
|
||||
|
||||
const BoardPage: FC<Props> = (): JSX.Element => {
|
||||
const jwtToken = useSelector(selectUserJwtToken)
|
||||
|
||||
if (jwtToken === undefined) return <p>Loading...</p>
|
||||
if (jwtToken) {
|
||||
return (
|
||||
<div className={styles.dayWishPage}>
|
||||
<div className={styles.dayWisContent}>
|
||||
<DayWishes />
|
||||
<DayWishesForm />
|
||||
<DDayInformations />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return <div>Besoin d'être identifié</div>
|
||||
}
|
||||
|
||||
// Fetch server-side data here
|
||||
export const loadData = (): AppThunk[] => [fetchVolunteerDayWishesSetIfNeed()]
|
||||
|
||||
export default memo(BoardPage)
|
16
src/pages/Board/index.tsx
Executable file
16
src/pages/Board/index.tsx
Executable file
@ -0,0 +1,16 @@
|
||||
import loadable from "@loadable/component"
|
||||
|
||||
import { Loading, ErrorBoundary } from "../../components"
|
||||
import { Props, loadData } from "./Board"
|
||||
|
||||
const BoardPage = loadable(() => import("./Board"), {
|
||||
fallback: <Loading />,
|
||||
})
|
||||
|
||||
export default (props: Props): JSX.Element => (
|
||||
<ErrorBoundary>
|
||||
<BoardPage {...props} />
|
||||
</ErrorBoundary>
|
||||
)
|
||||
|
||||
export { loadData }
|
9
src/pages/Board/styles.module.scss
Executable file
9
src/pages/Board/styles.module.scss
Executable file
@ -0,0 +1,9 @@
|
||||
@import "../../theme/mixins";
|
||||
|
||||
.dayWishPage {
|
||||
@include page-wrapper-center;
|
||||
}
|
||||
|
||||
.dayWisContent {
|
||||
@include page-content-wrapper(800px);
|
||||
}
|
@ -5,7 +5,7 @@ import { useSelector } from "react-redux"
|
||||
import { AppThunk } from "../../store"
|
||||
import { fetchVolunteerDayWishesSetIfNeed } from "../../store/volunteerDayWishesSet"
|
||||
import { selectUserJwtToken } from "../../store/auth"
|
||||
import DayWishes from "../../components/VolunteerBoard/DayWishes/DayWishes"
|
||||
import DayWishes from "../../components/VolunteerBoard/DayWishesForm/DayWishesForm"
|
||||
import DDayInformations from "../../components/VolunteerBoard/DDayInformations/DDaysInformations"
|
||||
import styles from "./styles.module.scss"
|
||||
|
||||
|
@ -4,6 +4,7 @@ import App from "../app"
|
||||
import AsyncHome, { loadData as loadHomeData } from "../pages/Home"
|
||||
import AsyncPreRegisterPage, { loadData as loadPreRegisterPage } from "../pages/PreRegister"
|
||||
import AsyncTeams, { loadData as loadTeamsData } from "../pages/Teams"
|
||||
import AsyncBoard, { loadData as loadBoardData } from "../pages/Board"
|
||||
import AsyncDayWishes, { loadData as loadDayWishesData } from "../pages/DayWishes"
|
||||
import AsyncTeamWishes, { loadData as loadTeamWishesData } from "../pages/TeamWishes"
|
||||
import AsyncWish, { loadData as loadWishData } from "../pages/Wish"
|
||||
@ -60,6 +61,11 @@ export default [
|
||||
component: AsyncWish,
|
||||
loadData: loadWishData,
|
||||
},
|
||||
{
|
||||
path: "/board",
|
||||
component: AsyncBoard,
|
||||
loadData: loadBoardData,
|
||||
},
|
||||
{
|
||||
component: NotFound,
|
||||
},
|
||||
|
@ -29,8 +29,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
@mixin inner-content-wrapper() {
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: $color-grey-lighter;
|
||||
}
|
||||
|
||||
@mixin clear-ul-style {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
@mixin vertical-center {
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
$color-white: #fff;
|
||||
$color-black: #000;
|
||||
$color-red: #f00;
|
||||
$color-orange: #ea4d0a;
|
||||
$color-yellow: #fdd137;
|
||||
$color-grey-dark: #555;
|
||||
|
Loading…
x
Reference in New Issue
Block a user