add board to home page

This commit is contained in:
memeriau 2022-03-13 19:49:39 +01:00
parent b93da3e119
commit 850d5e9da6
17 changed files with 253 additions and 162 deletions

View File

@ -1,7 +1,7 @@
import _ from "lodash"
import React, { memo, useCallback, useEffect, useRef, useState } from "react"
import isNode from "detect-node"
import { useDispatch, useSelector } from "react-redux"
import { shallowEqual, useDispatch, useSelector } from "react-redux"
import classnames from "classnames"
import { fetchVolunteerNotifsSet } from "../../store/volunteerNotifsSet"
import styles from "./styles.module.scss"
@ -9,15 +9,22 @@ import { selectUserJwtToken } from "../../store/auth"
import { VolunteerNotifs } from "../../services/volunteers"
// import { TeamWishesForm } from ".."
import { fetchFor as fetchForTeamWishesForm } from "../VolunteerBoard/TeamWishesForm/TeamWishesForm"
import { AppState } from "../../store"
import Block from "../ui/Content/ContentBlock"
interface Props {
// eslint-disable-next-line react/require-default-props
volunteerNotifs?: VolunteerNotifs
}
let prevNotifs: VolunteerNotifs | undefined
const Notifications = ({ volunteerNotifs }: Props): JSX.Element | null => {
const Notifications = (): JSX.Element | null => {
const dispatch = useDispatch()
const jwtToken = useSelector(selectUserJwtToken)
const volunteerNotifs = useSelector((state: AppState) => {
const notifs = state.volunteerNotifsSet?.entity
if (notifs) {
prevNotifs = notifs
return notifs
}
return prevNotifs
}, shallowEqual)
const hidden = volunteerNotifs?.hiddenNotifs || []
const notifs: JSX.Element[] = []
@ -36,13 +43,12 @@ const Notifications = ({ volunteerNotifs }: Props): JSX.Element | null => {
if (!_.includes(hidden, 1)) {
notifs.push(
<div key="1">
<div className={styles.notificationsPage}>
<div className={styles.notificationsContent}>
<form onSubmit={onSubmit1}>
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>
</div>
@ -50,7 +56,6 @@ const Notifications = ({ volunteerNotifs }: Props): JSX.Element | null => {
</form>
</div>
</div>
</div>
)
}
@ -80,7 +85,6 @@ const Notifications = ({ volunteerNotifs }: Props): JSX.Element | null => {
if (!_.includes(hidden, 2)) {
notifs.push(
<div key="2">
<div className={styles.notificationsPage}>
<div className={styles.notificationsContent}>
<div className={styles.formLine} key="line-participation">
<form onSubmit={onSubmit2}>
@ -140,7 +144,6 @@ const Notifications = ({ volunteerNotifs }: Props): JSX.Element | null => {
</div>
</div>
</div>
</div>
)
}
@ -155,7 +158,6 @@ const Notifications = ({ volunteerNotifs }: Props): JSX.Element | null => {
if (!_.includes(hidden, 3)) {
notifs.push(
<div key="3">
<div className={styles.notificationsPage}>
<div className={styles.notificationsContent}>
<form onSubmit={onSubmit3}>
<div
@ -177,7 +179,6 @@ const Notifications = ({ volunteerNotifs }: Props): JSX.Element | null => {
</form>
</div>
</div>
</div>
)
}
@ -381,16 +382,15 @@ Tu n'y es absolument pas obligé(e) ! C'est juste plus pratique.
if (notifs.length === 0) {
notifs.push(
<div key="pushNotifs">
<div className={styles.pushNotificationsPage}>
<div className={styles.pushNotificationsContent}>
<Block title="Notifications">
<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 spécifiquement pour toi ?<br />
<span className={styles.sousMessage}>
(Ça nous simplifierait la vie, on a des soucis à contacter les
bénévoles par email.)
@ -418,12 +418,11 @@ 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>
</div>
</div>
</Block>
</div>
)
}

View File

@ -6,7 +6,7 @@
}
.notificationsContent {
@include page-content-wrapper;
@include inner-content-wrapper;
}
.pushNotificationsPage {
@ -14,7 +14,7 @@
}
.pushNotificationsContent {
@include page-content-wrapper;
@include inner-content-wrapper;
}
.notifIntro {

View File

@ -6,16 +6,29 @@ 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"
const Board: FC = (): JSX.Element => (
<div>
<>
<ContentTitle title="Pour le jour J" />
<DayWishes />
<DayWishesFormModal />
<ParticipationDetails />
<ParticipationDetailsFormModal />
<TeamWishes />
<TeamWishesFormModal />
</div>
</>
)
export default memo(withUserConnected(Board))
export const fetchFor = [
fetchVolunteerDayWishesSetIfNeed,
fetchVolunteerParticipationDetailsSetIfNeed,
fetchTeamListIfNeed,
fetchVolunteerTeamWishesSetIfNeed,
]

View File

@ -65,7 +65,7 @@ const TeamWishesForm: FC<Props> = ({ afterSubmit }): JSX.Element | null => {
{selection.map((item) => {
const team = teams.find((t: any) => t.id === item)
if (!team) return null
return <li>{team.name}</li>
return <li key={team.id}>{team.name}</li>
})}
</ol>
<div className={styles.commentWrapper}>

View File

@ -0,0 +1,8 @@
import { FC, memo } from "react"
import styles from "./styles.module.scss"
const VolunteerConfirmation: FC = (): JSX.Element => (
<div className={styles.root}>&#10003; Tu es bénévole pour le festival de 2022. Merci !</div>
)
export default memo(VolunteerConfirmation)

View File

@ -0,0 +1,7 @@
@import "../../theme/variables";
.root {
margin-bottom: 10px;
text-align: center;
color: $color-green;
}

View File

@ -12,6 +12,7 @@ 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,
@ -28,4 +29,5 @@ export {
VolunteerList,
VolunteerSet,
WishAdd,
fetchForBoardForms,
}

View File

@ -0,0 +1,21 @@
import { FC, memo, ReactNode } from "react"
import styles from "./styles.module.scss"
import ContentTitle from "./ContentTitle"
interface Props {
children: ReactNode
title?: string | null
}
const ContentBlock: FC<Props> = ({ children, title }): JSX.Element => (
<div>
{title && <ContentTitle title={title} />}
<div className={styles.content}>{children}</div>
</div>
)
ContentBlock.defaultProps = {
title: null,
}
export default memo(ContentBlock)

View File

@ -0,0 +1,12 @@
import { FC, memo } from "react"
import styles from "./styles.module.scss"
interface Props {
title: string
}
const ContentTitle: FC<Props> = ({ title }): JSX.Element => (
<h2 className={styles.title}>{title}</h2>
)
export default memo(ContentTitle)

View File

@ -0,0 +1,12 @@
@import "../../../theme/mixins";
.title {
margin: 30px 10px 0;
padding: 0;
font-weight: 600;
font-size: 1.1em;
}
.content {
@include inner-content-wrapper;
}

View File

@ -1,4 +1,4 @@
@import "../../theme/mixins";
@import "../../../theme/mixins";
.pageWrapper {
@include page-wrapper-center;

View File

@ -4,7 +4,7 @@ import { useSelector } from "react-redux"
import { AppThunk } from "../../store"
import { selectUserJwtToken } from "../../store/auth"
import Page from "../../components/Page/Page"
import Page from "../../components/ui/Page/Page"
import Board from "../../components/VolunteerBoard/Board"
import { fetchVolunteerDayWishesSetIfNeed } from "../../store/volunteerDayWishesSet"
import { fetchVolunteerParticipationDetailsSetIfNeed } from "../../store/volunteerParticipationDetailsSet"

View File

@ -1,35 +1,33 @@
import { FC, memo } from "react"
import { RouteComponentProps, Link } from "react-router-dom"
import { useSelector, shallowEqual } from "react-redux"
import { useSelector } from "react-redux"
import { Helmet } from "react-helmet"
import { AppState, AppThunk } from "../../store"
import { LoginForm, Notifications, fetchForTeamWishesForm } from "../../components"
import { AppThunk } from "../../store"
import { LoginForm, Notifications, fetchForBoardForms } from "../../components"
import styles from "./styles.module.scss"
import { fetchVolunteerNotifsSetIfNeed } from "../../store/volunteerNotifsSet"
import { VolunteerNotifs } from "../../services/volunteers"
import { fetchVolunteerNotifsSetIfNeed, hasWaitingNotifs } from "../../store/volunteerNotifsSet"
import { selectUserJwtToken } from "../../store/auth"
import Board from "../../components/VolunteerBoard/Board"
import Page from "../../components/ui/Page/Page"
import VolunteerConfirmation from "../../components/VolunteerConfirmation/VolunteerConfirmation"
export type Props = RouteComponentProps
let prevNotifs: VolunteerNotifs | undefined
const HomePage: FC<Props> = (): JSX.Element => {
const jwtToken = useSelector(selectUserJwtToken)
const volunteerNotifs = useSelector((state: AppState) => {
const notifs = state.volunteerNotifsSet?.entity
if (notifs) {
prevNotifs = notifs
return notifs
}
return prevNotifs
}, shallowEqual)
const waitingNotifs = useSelector(hasWaitingNotifs)
if (jwtToken === undefined) return <p>Loading...</p>
if (jwtToken) {
return <Notifications volunteerNotifs={volunteerNotifs} />
return (
<Page>
{!waitingNotifs && <VolunteerConfirmation />}
<Notifications />
{!waitingNotifs && <Board />}
</Page>
)
}
return (
<div>
@ -51,7 +49,7 @@ const HomePage: FC<Props> = (): JSX.Element => {
// Fetch server-side data here
export const loadData = (): AppThunk[] => [
fetchVolunteerNotifsSetIfNeed(),
...fetchForTeamWishesForm.map((f) => f()),
...fetchForBoardForms.map((f) => f()),
]
export default memo(HomePage)

View File

@ -4,7 +4,7 @@ import { useSelector } from "react-redux"
import { AppThunk } from "../../store"
import { selectUserJwtToken } from "../../store/auth"
import Page from "../../components/Page/Page"
import Page from "../../components/ui/Page/Page"
import { fetchVolunteerListIfNeed } from "../../store/volunteerList"
export type Props = RouteComponentProps

View File

@ -1,4 +1,5 @@
import { PayloadAction, createSlice } from "@reduxjs/toolkit"
import { PayloadAction, createSlice, createSelector } from "@reduxjs/toolkit"
import get from "lodash/get"
import { StateRequest, toastError, elementFetch } from "./utils"
import { VolunteerNotifs } from "../services/volunteers"
@ -57,3 +58,21 @@ export const fetchVolunteerNotifsSetIfNeed =
return null
}
export const openedNotifsIds = [1, 2, 3]
export const selectVolunteerNotifsSetState = (state: AppState): StateVolunteerNotifsSet =>
state.volunteerNotifsSet
export const selectHiddenNotifs = createSelector(selectVolunteerNotifsSetState, (notifState) =>
get(notifState, "entity.hiddenNotifs", [])
)
export const selectWaitingsNotifs = createSelector(selectHiddenNotifs, (hidden) =>
openedNotifsIds.filter((id) => !hidden.find((hiddenId: number) => hiddenId === id))
)
export const hasWaitingNotifs = createSelector(
selectWaitingsNotifs,
(waiting) => waiting.length > 0
)

View File

@ -37,7 +37,7 @@
}
@mixin inner-content-wrapper() {
margin: 10px 0;
margin: 5px 0 10px;
padding: 10px;
border-radius: 5px;
background-color: $color-grey-lighter;