From e0c2c74e7b1c2618aa64825792a813eb55ef1505 Mon Sep 17 00:00:00 2001 From: Guillaume Cauchois Date: Tue, 3 Dec 2024 16:21:29 +0100 Subject: [PATCH 01/11] feat(Messaging): Add Messaging Suggestion --- .../MessagingConversation.tsx | 55 +++++++++--- .../MessagingSuggestions/Item/Item.styles.ts | 11 +++ .../MessagingSuggestions/Item/Item.tsx | 17 ++++ .../MessagingSuggestions.styles.ts | 38 +++++++++ .../MessagingSuggestions.tsx | 85 +++++++++++++++++++ .../MessagingSuggestions.types.ts | 4 + .../messaging/messaging.selectors.ts | 3 + src/use-cases/messaging/messaging.slice.ts | 6 ++ 8 files changed, 205 insertions(+), 14 deletions(-) create mode 100644 src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/Item/Item.styles.ts create mode 100644 src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/Item/Item.tsx create mode 100644 src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.styles.ts create mode 100644 src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx create mode 100644 src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.types.ts diff --git a/src/components/backoffice/messaging/MessagingConversation/MessagingConversation.tsx b/src/components/backoffice/messaging/MessagingConversation/MessagingConversation.tsx index 877a665bf..f28410a59 100644 --- a/src/components/backoffice/messaging/MessagingConversation/MessagingConversation.tsx +++ b/src/components/backoffice/messaging/MessagingConversation/MessagingConversation.tsx @@ -1,18 +1,31 @@ -import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'; +import React, { + useEffect, + useLayoutEffect, + useMemo, + useRef, + useState, +} from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { MessagingEmptyState } from '../MessagingEmptyState'; import { Button } from 'src/components/utils'; import { LucidIcon } from 'src/components/utils/Icons/LucidIcon'; import { DELAY_REFRESH_CONVERSATIONS } from 'src/constants'; +import { USER_ROLES } from 'src/constants/users'; import { useIsMobile } from 'src/hooks/utils'; -import { selectCurrentUserId } from 'src/use-cases/current-user'; +import { + selectCurrentUser, + selectCurrentUserId, +} from 'src/use-cases/current-user'; import { messagingActions, selectSelectedConversation, selectSelectedConversationId, selectPinnedInfo, } from 'src/use-cases/messaging'; -import { selectConversationParticipantsAreDeleted } from 'src/use-cases/messaging/messaging.selectors'; +import { + selectConversationParticipantsAreDeleted, + selectNewMessage, +} from 'src/use-cases/messaging/messaging.selectors'; import { MessagingConversationContainer, MessagingInput, @@ -23,10 +36,12 @@ import { import { MessagingConversationHeader } from './MessagingConversationHeader/MessagingConversationHeader'; import { MessagingMessage } from './MessagingMessage/MessagingMessage'; import { MessagingPinnedInfo } from './MessagingPinnedInfo/MessagingPinnedInfo'; +import { MessagingSuggestions } from './MessagingSuggestions/MessagingSuggestions'; export const MessagingConversation = () => { const dispatch = useDispatch(); const isMobile = useIsMobile(); + const currentUser = useSelector(selectCurrentUser); const currentUserId = useSelector(selectCurrentUserId); const selectedConversationId = useSelector(selectSelectedConversationId); const selectedConversation = useSelector(selectSelectedConversation); @@ -34,10 +49,17 @@ export const MessagingConversation = () => { selectConversationParticipantsAreDeleted ); const pinnedInfo = useSelector(selectPinnedInfo); - const [newMessage, setNewMessage] = useState(''); + const newMessage = useSelector(selectNewMessage); const [scrollBehavior, setScrollBehavior] = useState( 'instant' as ScrollBehavior ); + const displaySuggestions = useMemo(() => { + return ( + selectedConversationId === 'new' && + currentUser && + currentUser.role === USER_ROLES.CANDIDATE + ); + }, [currentUser, selectedConversationId]); const messagesEndRef = useRef(null); const messageInputRef = useRef(null); @@ -81,7 +103,6 @@ export const MessagingConversation = () => { selectedConversationId === 'new' ? undefined : selectedConversation.id, }; dispatch(messagingActions.postMessageRequested(body)); - setNewMessage(''); adjustMessageHeight(); }; @@ -146,14 +167,20 @@ export const MessagingConversation = () => { <> {pinnedInfo && } - - {selectedConversation && - selectedConversation.messages && - selectedConversation.messages.map((message) => ( - - ))} -
- + + {displaySuggestions ? ( + + ) : ( + + {selectedConversation && + selectedConversation.messages && + selectedConversation.messages.map((message) => ( + + ))} +
+ + )} + {/* Bloc de rédaction d'un message */} @@ -163,7 +190,7 @@ export const MessagingConversation = () => { placeholder="Ecrivez votre message" value={newMessage} onChange={(e) => { - setNewMessage(e.target.value); + dispatch(messagingActions.setNewMessage(e.target.value)); }} disabled={conversationParticipantsAreDeleted} /> diff --git a/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/Item/Item.styles.ts b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/Item/Item.styles.ts new file mode 100644 index 000000000..fce4b13ed --- /dev/null +++ b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/Item/Item.styles.ts @@ -0,0 +1,11 @@ +import styled from 'styled-components'; +import { COLORS } from 'src/constants/styles'; + +export const ItemContainer = styled.div` + display: flex; + background: ${COLORS.hoverBlue}; + padding: 8px 10px; + border-radius: 50px; + cursor: pointer; + text-wrap: nowrap; +`; diff --git a/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/Item/Item.tsx b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/Item/Item.tsx new file mode 100644 index 000000000..23f438b13 --- /dev/null +++ b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/Item/Item.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { MessagingSuggestionItem } from '../MessagingSuggestions.types'; +import { Text } from 'src/components/utils'; +import { ItemContainer } from './Item.styles'; + +export interface ItemProps { + suggestion: MessagingSuggestionItem; + onClick?: () => void; +} + +export const Item = ({ suggestion, onClick }: ItemProps) => { + return ( + + {suggestion.name} + + ); +}; diff --git a/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.styles.ts b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.styles.ts new file mode 100644 index 000000000..224200769 --- /dev/null +++ b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.styles.ts @@ -0,0 +1,38 @@ +import styled from 'styled-components'; + +export const MessagingSuggestionsContainer = styled.div` + display: flex; + flex-direction: column; + width: 100%; + overflow-y: auto; + padding: 20px; + box-sizing: border-box; + flex: auto; + gap: 30px; + justify-content: center; +`; + +export const MessagingSuggestionsExplanation = styled.div` + display: flex; + flex-direction: column; + flex: 1; + justify-content: center; + align-items: center; + height: 100%; + gap: 20px; + + h3 { + margin: 0; + } + p { + margin: 0; + text-align: center; + } +`; + +export const MessagingSuggestionsListContainer = styled.div` + display: flex; + flex-direction: row; + gap: 20px; + flex-wrap: wrap; +`; diff --git a/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx new file mode 100644 index 000000000..7acd58d4e --- /dev/null +++ b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx @@ -0,0 +1,85 @@ +import React, { useMemo } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { IlluConversation } from 'assets/icons/icons'; +import { H3 } from 'src/components/utils/Headings/H3'; +import { selectCurrentUser } from 'src/use-cases/current-user'; +import { messagingActions, selectNewMessage } from 'src/use-cases/messaging'; +import { Item } from './Item/Item'; +import { + MessagingSuggestionsContainer, + MessagingSuggestionsExplanation, + MessagingSuggestionsListContainer, +} from './MessagingSuggestions.styles'; +import { MessagingSuggestionItem } from './MessagingSuggestions.types'; + +export const MessagingSuggestions = () => { + const dispatch = useDispatch(); + const newMessage = useSelector(selectNewMessage); + const currentUser = useSelector(selectCurrentUser); + + const suggestions = useMemo(() => { + if (!currentUser) { + return []; + } + return [ + { + name: 'Améliorer mes candidatures', + message: `Bonjour, je suis ${currentUser.firstName},\nJe cherche des conseils pour trouver un emploi. Pouvez-vous m’aider à améliorer mon CV et mes candidatures ?\nMerci d'avance`, + }, + { + name: 'Préparer un entretien', + message: `Bonjour, je suis ${currentUser.firstName},\nJ’ai passé un entretien récemment, mais je ne suis pas sûr de ma prestation. Pouvez-vous m’aider à m’améliorer pour les prochains ?\nMerci d'avance`, + }, + { + name: "M'orienter professionnellement", + message: `Bonjour, je suis ${currentUser.firstName},\nJ’aimerais discuter de mon orientation professionnelle. Comment choisir un métier qui correspond à mes compétences et mes envies ?\nMerci d'avance`, + }, + { + name: "M'organiser pour mes recherches", + message: `Bonjour, je suis ${currentUser.firstName},\nJe veux organiser ma recherche d’emploi plus efficacement. Avez-vous des conseils pour mieux planifier mes démarches ?\nMerci d'avance`, + }, + { + name: 'Comprendre le marché du travail', + message: `Bonjour, je suis ${ + currentUser.firstName + },\nPourriez-vous m’en dire plus sur les métiers qui recrutent dans mon secteur ${ + currentUser.userProfile?.department + ? `- ${currentUser.userProfile.department}` + : '' + } ? Je veux maximiser mes chances.\nMerci d'avance`, + }, + ] as MessagingSuggestionItem[]; + }, [currentUser]); + + const bindSelectedSuggestion = (suggestion: MessagingSuggestionItem) => { + dispatch(messagingActions.setNewMessage(suggestion.message)); + }; + + return ( + + {newMessage.length <= 0 && ( + <> + + +

+

+ Choisissez un sujet ci-dessous et envoyez votre premier message en + toute simplicité +

+ + + {suggestions.map((suggestion) => ( + { + bindSelectedSuggestion(suggestion); + }} + /> + ))} + + + )} + + ); +}; diff --git a/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.types.ts b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.types.ts new file mode 100644 index 000000000..06bcda5d9 --- /dev/null +++ b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.types.ts @@ -0,0 +1,4 @@ +export interface MessagingSuggestionItem { + name: string; + message: string; +} diff --git a/src/use-cases/messaging/messaging.selectors.ts b/src/use-cases/messaging/messaging.selectors.ts index 9a4c0adb6..a6ceb591b 100644 --- a/src/use-cases/messaging/messaging.selectors.ts +++ b/src/use-cases/messaging/messaging.selectors.ts @@ -30,3 +30,6 @@ export const selectConversationParticipantsAreDeleted = (state: RootState) => { return participant.userProfile === null; }); }; + +export const selectNewMessage = (state: RootState) => + state.messaging.newMessage; diff --git a/src/use-cases/messaging/messaging.slice.ts b/src/use-cases/messaging/messaging.slice.ts index 17af1fe8c..7c5d56747 100644 --- a/src/use-cases/messaging/messaging.slice.ts +++ b/src/use-cases/messaging/messaging.slice.ts @@ -25,6 +25,7 @@ export interface State { pinnedInfo: MessagingPinnedInfo; query: string; unseenConversationCount: number; + newMessage: string; } const initialState: State = { @@ -40,6 +41,7 @@ const initialState: State = { pinnedInfo: null, query: '', unseenConversationCount: 0, + newMessage: '', }; export const slice = createSlice({ @@ -125,6 +127,7 @@ export const slice = createSlice({ state.conversations.splice(selectedConvIdx, 1); state.conversations.unshift(conversation); } + state.newMessage = ''; }, }), ...getSelectedConversationAdapter.getReducers( @@ -150,6 +153,9 @@ export const slice = createSlice({ setPinnedInfo(state, action) { state.pinnedInfo = action.payload; }, + setNewMessage(state, action) { + state.newMessage = action.payload; + }, }, }); From a91d204534357c42ed18a09b222eab74cd7285a8 Mon Sep 17 00:00:00 2001 From: Guillaume Cauchois Date: Thu, 5 Dec 2024 15:11:50 +0100 Subject: [PATCH 02/11] feat: Add font-weight 500 / semibold --- assets/custom/entourage.less | 7 +++++++ assets/custom/entourage.print.less | 7 +++++++ public/static/css/uikit.entourage.print.css | 6 ++++++ src/components/utils/Headings/Headings.styles.ts | 14 +++++++------- src/components/utils/Headings/Headings.types.ts | 9 ++++++++- src/components/utils/Text/Text.styles.ts | 3 ++- src/styles/dist/css/uikit.entourage.css | 6 ++++++ src/styles/dist/css/uikit.entourage.min.css | 6 ++++++ src/styles/dist/css/uikit.entourage.print.css | 6 ++++++ 9 files changed, 55 insertions(+), 9 deletions(-) diff --git a/assets/custom/entourage.less b/assets/custom/entourage.less index d6df288a2..43d2bd876 100644 --- a/assets/custom/entourage.less +++ b/assets/custom/entourage.less @@ -24,6 +24,13 @@ font-display: swap; } +@font-face { + font-family: 'Poppins'; + font-weight: 500; + src: url('/static/fonts/Poppins-SemiBold.ttf') format('truetype'); + font-display: swap; +} + @media print { * { diff --git a/assets/custom/entourage.print.less b/assets/custom/entourage.print.less index 15927d151..5d6f0cb06 100644 --- a/assets/custom/entourage.print.less +++ b/assets/custom/entourage.print.less @@ -23,6 +23,13 @@ font-display: swap; } +@font-face { + font-family: 'Poppins'; + font-weight: 500; + src: url('/static/fonts/Poppins-SemiBold.ttf') format('truetype'); + font-display: swap; +} + //Font families @global-font-family: Poppins, sans-serif; @global-font-weight: normal; diff --git a/public/static/css/uikit.entourage.print.css b/public/static/css/uikit.entourage.print.css index 9319e619f..d20c46e19 100644 --- a/public/static/css/uikit.entourage.print.css +++ b/public/static/css/uikit.entourage.print.css @@ -12611,6 +12611,12 @@ iframe.uk-cover { src: url('/static/fonts/Poppins-Light.ttf') format('truetype'); font-display: swap; } +@font-face { + font-family: 'Poppins'; + font-weight: 500; + src: url('/static/fonts/Poppins-SemiBold.ttf') format('truetype'); + font-display: swap; +} * { -webkit-print-color-adjust: exact !important; } diff --git a/src/components/utils/Headings/Headings.styles.ts b/src/components/utils/Headings/Headings.styles.ts index 94083f14b..9832ce735 100644 --- a/src/components/utils/Headings/Headings.styles.ts +++ b/src/components/utils/Headings/Headings.styles.ts @@ -1,10 +1,10 @@ import styled from 'styled-components'; import { COLORS } from 'src/constants/styles'; -import { StyledHeadingProps } from './Headings.types'; +import { FONT_WEIGHTS, StyledHeadingProps } from './Headings.types'; export const StyledH1 = styled.h1` font-size: ${(props) => (props.mobile ? '24px' : '35px')}; - font-weight: ${(props) => props.weight}; + font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; color: ${(props) => { if (COLORS[props.color]) { return COLORS[props.color]; @@ -19,7 +19,7 @@ export const StyledH1 = styled.h1` export const StyledH2 = styled.h2` font-size: ${(props) => (props.mobile ? '20px' : '28px')}; - font-weight: ${(props) => props.weight}; + font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; color: ${(props) => { if (COLORS[props.color]) { return COLORS[props.color]; @@ -39,7 +39,7 @@ export const StyledH2 = styled.h2` `; export const StyledH3 = styled.h3` - font-weight: ${(props) => props.weight}; + font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; line-height: 36px; color: black; color: ${(props) => { @@ -56,7 +56,7 @@ export const StyledH3 = styled.h3` `; export const StyledH4 = styled.h4` - font-weight: ${(props) => props.weight}; + font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; line-height: 24px; color: ${(props) => { if (COLORS[props.color]) { @@ -72,7 +72,7 @@ export const StyledH4 = styled.h4` `; export const StyledH5 = styled.h5` - font-weight: ${(props) => props.weight}; + font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; line-height: 24px; margin-top: 0; color: ${(props) => { @@ -90,7 +90,7 @@ export const StyledH5 = styled.h5` export const StyledH6 = styled.h6` font-size: 14px; - font-weight: ${(props) => props.weight}; + font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; line-height: 14px; color: ${(props) => { if (COLORS[props.color]) { diff --git a/src/components/utils/Headings/Headings.types.ts b/src/components/utils/Headings/Headings.types.ts index 6643201a5..15748ed5b 100644 --- a/src/components/utils/Headings/Headings.types.ts +++ b/src/components/utils/Headings/Headings.types.ts @@ -1,4 +1,11 @@ -export type WeightProps = 'normal' | 'bold' | 'lighter'; +export const FONT_WEIGHTS = { + lighter: 'lighter', + normal: 'normal', + semibold: '500', + bold: 'bold', +}; + +export type WeightProps = (typeof FONT_WEIGHTS)[keyof typeof FONT_WEIGHTS]; interface HeadingBasicProps { color?: string; diff --git a/src/components/utils/Text/Text.styles.ts b/src/components/utils/Text/Text.styles.ts index b7b9896fb..237984687 100644 --- a/src/components/utils/Text/Text.styles.ts +++ b/src/components/utils/Text/Text.styles.ts @@ -1,4 +1,5 @@ import styled from 'styled-components'; +import { FONT_WEIGHTS } from '../Headings/Headings.types'; import { COLORS } from 'src/constants/styles'; import { TextProps } from './Text.types'; @@ -21,7 +22,7 @@ const colors: { [K in NonNullable]: string } = { export const StyledText = styled.div` padding: 0; margin: 0; - font-weight: ${({ weight }) => weight}; + font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; font-size: ${({ size }) => sizes[size]}px; line-height: ${({ size }) => sizes[size] * 1.5}px; color: ${({ color }) => colors[color]}; diff --git a/src/styles/dist/css/uikit.entourage.css b/src/styles/dist/css/uikit.entourage.css index 96e6b5bb2..41008c3c7 100644 --- a/src/styles/dist/css/uikit.entourage.css +++ b/src/styles/dist/css/uikit.entourage.css @@ -13529,6 +13529,12 @@ iframe.uk-cover { src: url('/static/fonts/Poppins-Light.ttf') format('truetype'); font-display: swap; } +@font-face { + font-family: 'Poppins'; + font-weight: 500; + src: url('/static/fonts/Poppins-SemiBold.ttf') format('truetype'); + font-display: swap; +} @media print { * { -webkit-print-color-adjust: exact !important; diff --git a/src/styles/dist/css/uikit.entourage.min.css b/src/styles/dist/css/uikit.entourage.min.css index ee1dfcfca..f6daf19d7 100644 --- a/src/styles/dist/css/uikit.entourage.min.css +++ b/src/styles/dist/css/uikit.entourage.min.css @@ -10496,6 +10496,12 @@ iframe.uk-cover { src: url('/static/fonts/Poppins-Light.ttf') format('truetype'); font-display: swap; } +@font-face { + font-family: 'Poppins'; + font-weight: 500; + src: url('/static/fonts/Poppins-SemiBold.ttf') format('truetype'); + font-display: swap; +} @media print { * { -webkit-print-color-adjust: exact !important; diff --git a/src/styles/dist/css/uikit.entourage.print.css b/src/styles/dist/css/uikit.entourage.print.css index 05ad8f614..2a6adf970 100644 --- a/src/styles/dist/css/uikit.entourage.print.css +++ b/src/styles/dist/css/uikit.entourage.print.css @@ -13388,6 +13388,12 @@ iframe.uk-cover { src: url('/static/fonts/Poppins-Light.ttf') format('truetype'); font-display: swap; } +@font-face { + font-family: 'Poppins'; + font-weight: 500; + src: url('/static/fonts/Poppins-SemiBold.ttf') format('truetype'); + font-display: swap; +} * { -webkit-print-color-adjust: exact !important; } From 053dce01930f2caa745c92dff28984c9d66a7b16 Mon Sep 17 00:00:00 2001 From: Guillaume Cauchois Date: Thu, 5 Dec 2024 15:19:46 +0100 Subject: [PATCH 03/11] fix: missing .min --- src/styles/dist/css/uikit.entourage.print.min.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/styles/dist/css/uikit.entourage.print.min.css b/src/styles/dist/css/uikit.entourage.print.min.css index 03c74c7fe..7f89d6b34 100644 --- a/src/styles/dist/css/uikit.entourage.print.min.css +++ b/src/styles/dist/css/uikit.entourage.print.min.css @@ -10355,6 +10355,12 @@ iframe.uk-cover { src: url('/static/fonts/Poppins-Light.ttf') format('truetype'); font-display: swap; } +@font-face { + font-family: 'Poppins'; + font-weight: 500; + src: url('/static/fonts/Poppins-SemiBold.ttf') format('truetype'); + font-display: swap; +} * { -webkit-print-color-adjust: exact !important; } From 410208ca47780522622bb58a5a6faac4380f90fc Mon Sep 17 00:00:00 2001 From: Guillaume Cauchois Date: Thu, 5 Dec 2024 15:30:41 +0100 Subject: [PATCH 04/11] fix: remove 500 semibold from existing elements --- assets/custom/entourage.less | 4 ---- src/components/cards/CandidatCard.styles.tsx | 1 - .../HeaderConnectedContent/HeaderConnectedContent.desktop.tsx | 1 - .../HeaderConnectedContent/HeaderConnectedContent.styles.ts | 1 - src/styles/dist/css/uikit.entourage.css | 3 --- src/styles/dist/css/uikit.entourage.min.css | 3 --- 6 files changed, 13 deletions(-) diff --git a/assets/custom/entourage.less b/assets/custom/entourage.less index 43d2bd876..0e14359ea 100644 --- a/assets/custom/entourage.less +++ b/assets/custom/entourage.less @@ -302,10 +302,6 @@ mark, .mark-animated > * > * > * > * { .ent-subnav { margin-bottom: 30px !important; - li.uk-active { - font-weight: 500; - } - > * { padding-left: 40px; } diff --git a/src/components/cards/CandidatCard.styles.tsx b/src/components/cards/CandidatCard.styles.tsx index 87f7b97da..a351b5615 100644 --- a/src/components/cards/CandidatCard.styles.tsx +++ b/src/components/cards/CandidatCard.styles.tsx @@ -65,7 +65,6 @@ export const CandidatCardPictureOverlay = styled.div` margin: 0; &.name { font-size: 25px; - font-weight: 500; } } `; diff --git a/src/components/headers/HeaderConnected/HeaderConnectedContent/HeaderConnectedContent.desktop.tsx b/src/components/headers/HeaderConnected/HeaderConnectedContent/HeaderConnectedContent.desktop.tsx index 77c994f72..32fa155ac 100644 --- a/src/components/headers/HeaderConnected/HeaderConnectedContent/HeaderConnectedContent.desktop.tsx +++ b/src/components/headers/HeaderConnected/HeaderConnectedContent/HeaderConnectedContent.desktop.tsx @@ -62,7 +62,6 @@ export const HeaderConnectedContentDesktop = ({ className="uk-padding-small uk-padding-remove-vertical" style={{ height: 80, - fontWeight: 500, fontSize: '1rem', textTransform: 'none', display: 'flex', diff --git a/src/components/headers/HeaderConnected/HeaderConnectedContent/HeaderConnectedContent.styles.ts b/src/components/headers/HeaderConnected/HeaderConnectedContent/HeaderConnectedContent.styles.ts index 124400ff9..32f659136 100644 --- a/src/components/headers/HeaderConnected/HeaderConnectedContent/HeaderConnectedContent.styles.ts +++ b/src/components/headers/HeaderConnected/HeaderConnectedContent/HeaderConnectedContent.styles.ts @@ -29,7 +29,6 @@ export const StyledConnectedItem = styled.li` color: ${({ color }) => { return COLORS[color] || COLORS.black; }}; - font-weight: 500; } &.hasSubMenu { diff --git a/src/styles/dist/css/uikit.entourage.css b/src/styles/dist/css/uikit.entourage.css index 41008c3c7..9a7d68619 100644 --- a/src/styles/dist/css/uikit.entourage.css +++ b/src/styles/dist/css/uikit.entourage.css @@ -13594,9 +13594,6 @@ mark, .ent-subnav { margin-bottom: 30px !important; } -.ent-subnav li.uk-active { - font-weight: 500; -} .ent-subnav > * { padding-left: 40px; } diff --git a/src/styles/dist/css/uikit.entourage.min.css b/src/styles/dist/css/uikit.entourage.min.css index f6daf19d7..21e93d49c 100644 --- a/src/styles/dist/css/uikit.entourage.min.css +++ b/src/styles/dist/css/uikit.entourage.min.css @@ -10561,9 +10561,6 @@ mark { .ent-subnav { margin-bottom: 30px !important; } -.ent-subnav li.uk-active { - font-weight: 500; -} .ent-subnav > * { padding-left: 40px; } From ac80f3393f4de90ec850ac9605b618d23ab64187 Mon Sep 17 00:00:00 2001 From: Guillaume Cauchois Date: Fri, 6 Dec 2024 10:21:56 +0100 Subject: [PATCH 05/11] feat(Dashboard): add new card with next steps --- .../backoffice/dashboard/Dashboard.tsx | 4 +- .../DashboardNextSteps.styles.ts | 9 ++ .../DashboardNextSteps/DashboardNextSteps.tsx | 94 +++++++++++++++++++ .../DashboardNextSteps/Step/Step.style.ts | 24 +++++ .../DashboardNextSteps/Step/Step.tsx | 49 ++++++++++ .../useDashboardRecommendations.ts | 2 +- .../utils/Headings/Headings.styles.ts | 16 +++- 7 files changed, 191 insertions(+), 7 deletions(-) create mode 100644 src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.styles.ts create mode 100644 src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.tsx create mode 100644 src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.style.ts create mode 100644 src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.tsx diff --git a/src/components/backoffice/dashboard/Dashboard.tsx b/src/components/backoffice/dashboard/Dashboard.tsx index d4e8ff721..7c0c54da5 100644 --- a/src/components/backoffice/dashboard/Dashboard.tsx +++ b/src/components/backoffice/dashboard/Dashboard.tsx @@ -20,11 +20,11 @@ import { DashboardAlertWhatsappCoach } from './DashboardAlertWhatsappCoach/Dashb import { DashboardAvailabilityCard } from './DashboardAvailabilityCard'; import { DashboardLinkedUserCard } from './DashboardLinkedUserCard'; import { DashboardMessagingConversation } from './DashboardMessagingConversation'; +import { DashboardNextSteps } from './DashboardNextSteps/DashboardNextSteps'; import { DashboardProfileCard } from './DashboardProfileCard'; import { DashboardReadDocumentsCard } from './DashboardReadDocumentsCard'; import { DashboardRecommendationsCard } from './DashboardRecommendationsCard'; import { DashboardReferentCard } from './DashboardReferentCard'; -import { DashboardStepsCard } from './DashboardStepsCard'; import { DashboardToolboxCard } from './DashboardToolboxCard'; export const Dashboard = () => { @@ -54,7 +54,7 @@ export const Dashboard = () => { {isNormalUser && ( <> - + )} diff --git a/src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.styles.ts b/src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.styles.ts new file mode 100644 index 000000000..87b81d5b6 --- /dev/null +++ b/src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.styles.ts @@ -0,0 +1,9 @@ +import styled from 'styled-components'; + +export const StyledStepsContainer = styled.div` + display: grid; + width: 100%; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + justify-content: center; + gap: 40px; +`; diff --git a/src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.tsx b/src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.tsx new file mode 100644 index 000000000..300110868 --- /dev/null +++ b/src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.tsx @@ -0,0 +1,94 @@ +import React from 'react'; +import { useSelector } from 'react-redux'; +import { v4 as uuid } from 'uuid'; +import { + IlluBulleQuestion, + IlluCoeurMainsOuvertesBleu, + IlluCV, +} from 'assets/icons/icons'; +import { Card } from 'src/components/utils/Cards/Card/Card'; +import { USER_ROLES } from 'src/constants/users'; +import { useCandidateId } from 'src/hooks/queryParams/useCandidateId'; +import { selectCurrentUser } from 'src/use-cases/current-user'; +import { StyledStepsContainer } from './DashboardNextSteps.styles'; +import { Step } from './Step/Step'; + +export const DashboardNextSteps = () => { + const iconSizeProps = { width: 90, height: 90 }; + const candidateId = useCandidateId(); + const currentUser = useSelector(selectCurrentUser); + + const stepsByRole = { + [USER_ROLES.CANDIDATE]: [ + { + title: "S'inscrire au webinaire d'information", + icon: , + content: + 'Envie d’en savoir plus sur la plateforme Entourage pro. Inscrivez-vous au prochain webinaire d’information', + cta: { + label: "S'inscrire", + href: '/webinaire-d-information', + }, + }, + { + title: 'Faire mon CV Entourage pro', + icon: , + content: + 'L’objectif du CV Entourage Pro est de rendre visible et valoriser votre projet professionnel', + cta: { + label: 'Créer mon CV', + href: `/backoffice/candidat/${candidateId}/cv`, + }, + }, + { + title: 'Découvrir le réseau d’entraide ', + icon: , + content: + 'Retrouvez tous les coachs de la communauté et contactez les pour leur demander de l’aide et des conseils', + cta: { + label: 'Découvrir', + href: '/webinaire-d-information', + }, + }, + ], + [USER_ROLES.COACH]: [ + { + title: "S'inscrire au webinaire d'information", + icon: , + content: + 'Envie d’en savoir plus sur la plateforme Entourage pro. Inscrivez-vous au prochain webinaire d’information', + cta: { + label: "S'inscrire", + href: '/webinaire-d-information', + }, + }, + { + title: 'Découvrir le réseau d’entraide ', + icon: , + content: + 'Retrouvez tous les coachs de la communauté et contactez les pour leur demander de l’aide et des conseils', + cta: { + label: 'Découvrir', + href: '/webinaire-d-information', + }, + }, + ], + }; + + if (!currentUser || !currentUser.role) { + return null; + } + + const steps = stepsByRole[currentUser.role] || []; + + return ( + + + {steps.map((step) => { + const uuidValue = uuid(); + return ; + })} + + + ); +}; diff --git a/src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.style.ts b/src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.style.ts new file mode 100644 index 000000000..c6cb4644f --- /dev/null +++ b/src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.style.ts @@ -0,0 +1,24 @@ +import styled from 'styled-components'; +import { COLORS } from 'src/constants/styles'; + +export const StyledStepContainer = styled.div` + display: flex; + flex-direction: column; + gap: 14px; + justify-content: space-between; + padding: 20px; + border: ${COLORS.gray} 1px solid; + border-radius: 20px; +`; + +export const StyledStepImage = styled.div` + display: flex; + justify-content: center; + align-items: center; + height: 103px; +`; + +export const StyledStepBtnContainer = styled.div` + display: flex; + justify-content: center; +`; diff --git a/src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.tsx b/src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.tsx new file mode 100644 index 000000000..cf043f046 --- /dev/null +++ b/src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { Button } from 'src/components/utils/Button/Button'; +import { H5 } from 'src/components/utils/Headings'; +import { Text } from 'src/components/utils/Text/Text'; +import { COLORS } from 'src/constants/styles'; +import { + StyledStepBtnContainer, + StyledStepContainer, + StyledStepImage, +} from './Step.style'; + +export interface Step { + title: string; + content: string; + icon: React.ReactElement; + cta: { + label: string; + href: string; + }; +} + +export interface StepProps { + step: Step; +} + +export const Step = ({ step }: StepProps) => { + return ( + + {step.icon} +
+ {step.content} + + + + + ); +}; diff --git a/src/components/backoffice/dashboard/DashboardRecommendationsCard/useDashboardRecommendations.ts b/src/components/backoffice/dashboard/DashboardRecommendationsCard/useDashboardRecommendations.ts index 81cf5735a..92d375c7d 100644 --- a/src/components/backoffice/dashboard/DashboardRecommendationsCard/useDashboardRecommendations.ts +++ b/src/components/backoffice/dashboard/DashboardRecommendationsCard/useDashboardRecommendations.ts @@ -45,7 +45,7 @@ export function useDashboardRecommendations() { notificationsActions.addNotification({ type: 'danger', message: - 'Une erreur est survenue lors de la récupération des recommendations', + 'Une erreur est survenue lors de la récupération des recommandations', }) ); } diff --git a/src/components/utils/Headings/Headings.styles.ts b/src/components/utils/Headings/Headings.styles.ts index 9832ce735..491be53f8 100644 --- a/src/components/utils/Headings/Headings.styles.ts +++ b/src/components/utils/Headings/Headings.styles.ts @@ -4,6 +4,7 @@ import { FONT_WEIGHTS, StyledHeadingProps } from './Headings.types'; export const StyledH1 = styled.h1` font-size: ${(props) => (props.mobile ? '24px' : '35px')}; + line-height: 1.5; font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; color: ${(props) => { if (COLORS[props.color]) { @@ -15,10 +16,12 @@ export const StyledH1 = styled.h1` return COLORS.black; }}; text-align: ${(props) => (props.center ? 'center' : 'left')}; + margin: 0; `; export const StyledH2 = styled.h2` font-size: ${(props) => (props.mobile ? '20px' : '28px')}; + line-height: 1.5; font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; color: ${(props) => { if (COLORS[props.color]) { @@ -36,11 +39,12 @@ export const StyledH2 = styled.h2` span.orange { color: ${COLORS.primaryBlue}; } + margin: 0; `; export const StyledH3 = styled.h3` font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; - line-height: 36px; + line-height: 1.5; color: black; color: ${(props) => { if (COLORS[props.color]) { @@ -53,11 +57,12 @@ export const StyledH3 = styled.h3` }}; text-align: ${(props) => (props.center ? 'center' : 'left')}; font-size: ${(props) => (props.mobile ? '18px' : '24px')}; + margin: 0; `; export const StyledH4 = styled.h4` font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; - line-height: 24px; + line-height: 1.5; color: ${(props) => { if (COLORS[props.color]) { return COLORS[props.color]; @@ -69,11 +74,12 @@ export const StyledH4 = styled.h4` }}; text-align: ${(props) => (props.center ? 'center' : 'left')}; font-size: ${(props) => (props.mobile ? '16px' : '20px')}; + margin: 0; `; export const StyledH5 = styled.h5` font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; - line-height: 24px; + line-height: 1.5; margin-top: 0; color: ${(props) => { if (COLORS[props.color]) { @@ -86,12 +92,13 @@ export const StyledH5 = styled.h5` }}; text-align: ${(props) => (props.center ? 'center' : 'left')}; font-size: ${(props) => (props.mobile ? '14px' : '16px')}; + margin: 0; `; export const StyledH6 = styled.h6` font-size: 14px; font-weight: ${(props) => FONT_WEIGHTS[props.weight]}; - line-height: 14px; + line-height: 1.5; color: ${(props) => { if (COLORS[props.color]) { return COLORS[props.color]; @@ -102,4 +109,5 @@ export const StyledH6 = styled.h6` return COLORS.black; }}; text-align: ${(props) => (props.center ? 'center' : 'left')}; + margin: 0; `; From d4b017487b18e12ebd63da7bd61b6e91c9381bd8 Mon Sep 17 00:00:00 2001 From: Guillaume Cauchois Date: Mon, 16 Dec 2024 12:35:19 +0100 Subject: [PATCH 06/11] fix: use local newMessage in ConversationMessage instead of app store --- .nvmrc | 2 +- package.json | 1 + .../MessagingConversation.tsx | 20 ++++++++++++------- .../MessagingSuggestions.tsx | 17 ++++++++++------ .../messaging/messaging.selectors.ts | 3 --- src/use-cases/messaging/messaging.slice.ts | 6 ------ 6 files changed, 26 insertions(+), 23 deletions(-) diff --git a/.nvmrc b/.nvmrc index 37e391feb..5f09eed8d 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v16.17.0 +v18.20.3 diff --git a/package.json b/package.json index 88d326d79..65501db44 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "engines": { "node": "18.x" }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e", "scripts": { "dev": "node -r dotenv/config server-next.js", "next": "next", diff --git a/src/components/backoffice/messaging/MessagingConversation/MessagingConversation.tsx b/src/components/backoffice/messaging/MessagingConversation/MessagingConversation.tsx index f28410a59..a34489d85 100644 --- a/src/components/backoffice/messaging/MessagingConversation/MessagingConversation.tsx +++ b/src/components/backoffice/messaging/MessagingConversation/MessagingConversation.tsx @@ -22,10 +22,7 @@ import { selectSelectedConversationId, selectPinnedInfo, } from 'src/use-cases/messaging'; -import { - selectConversationParticipantsAreDeleted, - selectNewMessage, -} from 'src/use-cases/messaging/messaging.selectors'; +import { selectConversationParticipantsAreDeleted } from 'src/use-cases/messaging/messaging.selectors'; import { MessagingConversationContainer, MessagingInput, @@ -49,7 +46,7 @@ export const MessagingConversation = () => { selectConversationParticipantsAreDeleted ); const pinnedInfo = useSelector(selectPinnedInfo); - const newMessage = useSelector(selectNewMessage); + const [newMessage, setNewMessage] = useState(''); const [scrollBehavior, setScrollBehavior] = useState( 'instant' as ScrollBehavior ); @@ -76,6 +73,7 @@ export const MessagingConversation = () => { useEffect(() => { setScrollBehavior('instant' as ScrollBehavior); + setNewMessage(''); }, [selectedConversationId]); const scrollToBottom = () => { @@ -85,6 +83,10 @@ export const MessagingConversation = () => { }, 1000); }; + const onSuggestionClick = (suggestion) => { + setNewMessage(suggestion.message); + }; + const sendNewMessage = () => { if (selectedConversation === null) { return; @@ -103,6 +105,7 @@ export const MessagingConversation = () => { selectedConversationId === 'new' ? undefined : selectedConversation.id, }; dispatch(messagingActions.postMessageRequested(body)); + setNewMessage(''); adjustMessageHeight(); }; @@ -169,7 +172,10 @@ export const MessagingConversation = () => { {pinnedInfo && } {displaySuggestions ? ( - + ) : ( {selectedConversation && @@ -190,7 +196,7 @@ export const MessagingConversation = () => { placeholder="Ecrivez votre message" value={newMessage} onChange={(e) => { - dispatch(messagingActions.setNewMessage(e.target.value)); + setNewMessage(e.target.value); }} disabled={conversationParticipantsAreDeleted} /> diff --git a/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx index 7acd58d4e..d4e725734 100644 --- a/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx +++ b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx @@ -1,9 +1,8 @@ import React, { useMemo } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { IlluConversation } from 'assets/icons/icons'; import { H3 } from 'src/components/utils/Headings/H3'; import { selectCurrentUser } from 'src/use-cases/current-user'; -import { messagingActions, selectNewMessage } from 'src/use-cases/messaging'; import { Item } from './Item/Item'; import { MessagingSuggestionsContainer, @@ -12,9 +11,15 @@ import { } from './MessagingSuggestions.styles'; import { MessagingSuggestionItem } from './MessagingSuggestions.types'; -export const MessagingSuggestions = () => { - const dispatch = useDispatch(); - const newMessage = useSelector(selectNewMessage); +export interface MessagingSuggestionProps { + newMessage: string; + onSuggestionClick: (suggestion: MessagingSuggestionItem) => void; +} + +export const MessagingSuggestions = ({ + newMessage, + onSuggestionClick, +}: MessagingSuggestionProps) => { const currentUser = useSelector(selectCurrentUser); const suggestions = useMemo(() => { @@ -52,7 +57,7 @@ export const MessagingSuggestions = () => { }, [currentUser]); const bindSelectedSuggestion = (suggestion: MessagingSuggestionItem) => { - dispatch(messagingActions.setNewMessage(suggestion.message)); + onSuggestionClick(suggestion); }; return ( diff --git a/src/use-cases/messaging/messaging.selectors.ts b/src/use-cases/messaging/messaging.selectors.ts index a6ceb591b..9a4c0adb6 100644 --- a/src/use-cases/messaging/messaging.selectors.ts +++ b/src/use-cases/messaging/messaging.selectors.ts @@ -30,6 +30,3 @@ export const selectConversationParticipantsAreDeleted = (state: RootState) => { return participant.userProfile === null; }); }; - -export const selectNewMessage = (state: RootState) => - state.messaging.newMessage; diff --git a/src/use-cases/messaging/messaging.slice.ts b/src/use-cases/messaging/messaging.slice.ts index 7c5d56747..17af1fe8c 100644 --- a/src/use-cases/messaging/messaging.slice.ts +++ b/src/use-cases/messaging/messaging.slice.ts @@ -25,7 +25,6 @@ export interface State { pinnedInfo: MessagingPinnedInfo; query: string; unseenConversationCount: number; - newMessage: string; } const initialState: State = { @@ -41,7 +40,6 @@ const initialState: State = { pinnedInfo: null, query: '', unseenConversationCount: 0, - newMessage: '', }; export const slice = createSlice({ @@ -127,7 +125,6 @@ export const slice = createSlice({ state.conversations.splice(selectedConvIdx, 1); state.conversations.unshift(conversation); } - state.newMessage = ''; }, }), ...getSelectedConversationAdapter.getReducers( @@ -153,9 +150,6 @@ export const slice = createSlice({ setPinnedInfo(state, action) { state.pinnedInfo = action.payload; }, - setNewMessage(state, action) { - state.newMessage = action.payload; - }, }, }); From 3953e48d29b1ce9ae60ec714abc0c114fa318b68 Mon Sep 17 00:00:00 2001 From: Guillaume Cauchois Date: Mon, 16 Dec 2024 15:37:00 +0100 Subject: [PATCH 07/11] feat: add final handling for next steps --- .env.dist | 3 +- .../DashboardNextSteps/DashboardNextSteps.tsx | 41 ++++++++----------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/.env.dist b/.env.dist index e7b9220db..c396cebda 100644 --- a/.env.dist +++ b/.env.dist @@ -4,7 +4,8 @@ HEROKU_RELEASE_VERSION="v100" ##SENTRY SENTRY_AUTH_TOKEN= SENTRY_DSN= -##GOOGLE + +##ENTOURAGE-PRO WEBINAR_URL="" TOOLBOX_URL="" TOOLBOX_COACH_URL="" diff --git a/src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.tsx b/src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.tsx index 300110868..12324cd07 100644 --- a/src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.tsx +++ b/src/components/backoffice/dashboard/DashboardNextSteps/DashboardNextSteps.tsx @@ -18,18 +18,20 @@ export const DashboardNextSteps = () => { const candidateId = useCandidateId(); const currentUser = useSelector(selectCurrentUser); + const webinarStep = { + title: "S'inscrire au webinaire d'information", + icon: , + content: + 'Envie d’en savoir plus sur la plateforme Entourage pro. Inscrivez-vous au prochain webinaire d’information', + cta: { + label: "S'inscrire", + href: process.env.WEBINAR_URL, + }, + }; + const stepsByRole = { [USER_ROLES.CANDIDATE]: [ - { - title: "S'inscrire au webinaire d'information", - icon: , - content: - 'Envie d’en savoir plus sur la plateforme Entourage pro. Inscrivez-vous au prochain webinaire d’information', - cta: { - label: "S'inscrire", - href: '/webinaire-d-information', - }, - }, + webinarStep, { title: 'Faire mon CV Entourage pro', icon: , @@ -44,32 +46,23 @@ export const DashboardNextSteps = () => { title: 'Découvrir le réseau d’entraide ', icon: , content: - 'Retrouvez tous les coachs de la communauté et contactez les pour leur demander de l’aide et des conseils', + 'Retrouvez tous les coachs de la communauté et contactez-les pour leur demander de l’aide et des conseils', cta: { label: 'Découvrir', - href: '/webinaire-d-information', + href: '/backoffice/annuaire?role=Coach', }, }, ], [USER_ROLES.COACH]: [ - { - title: "S'inscrire au webinaire d'information", - icon: , - content: - 'Envie d’en savoir plus sur la plateforme Entourage pro. Inscrivez-vous au prochain webinaire d’information', - cta: { - label: "S'inscrire", - href: '/webinaire-d-information', - }, - }, + webinarStep, { title: 'Découvrir le réseau d’entraide ', icon: , content: - 'Retrouvez tous les coachs de la communauté et contactez les pour leur demander de l’aide et des conseils', + 'Retrouvez tous les candidats de la communauté et contactez-les pour leur proposer de l’aide et des conseils', cta: { label: 'Découvrir', - href: '/webinaire-d-information', + href: '/backoffice/annuaire?role=Candidat', }, }, ], From d3920523d71719dd3093ded870ea25a607d1d1a0 Mon Sep 17 00:00:00 2001 From: Guillaume Cauchois Date: Mon, 16 Dec 2024 15:41:04 +0100 Subject: [PATCH 08/11] fix: fw 500 on next step item title --- .../backoffice/dashboard/DashboardNextSteps/Step/Step.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.tsx b/src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.tsx index cf043f046..ca63589fe 100644 --- a/src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.tsx +++ b/src/components/backoffice/dashboard/DashboardNextSteps/Step/Step.tsx @@ -31,7 +31,7 @@ export const Step = ({ step }: StepProps) => { title={step.title} center color={COLORS.primaryBlue} - weight="normal" + weight="semibold" /> {step.content} From dcd8d1da0798a2b17f70e4d22af413d0cd2b0b2f Mon Sep 17 00:00:00 2001 From: Guillaume Cauchois Date: Mon, 16 Dec 2024 16:06:16 +0100 Subject: [PATCH 09/11] fix: messaging suggestions --- .../MessagingSuggestions/MessagingSuggestions.tsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx index d4e725734..1fdabc7ef 100644 --- a/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx +++ b/src/components/backoffice/messaging/MessagingConversation/MessagingSuggestions/MessagingSuggestions.tsx @@ -33,7 +33,7 @@ export const MessagingSuggestions = ({ }, { name: 'Préparer un entretien', - message: `Bonjour, je suis ${currentUser.firstName},\nJ’ai passé un entretien récemment, mais je ne suis pas sûr de ma prestation. Pouvez-vous m’aider à m’améliorer pour les prochains ?\nMerci d'avance`, + message: `Bonjour, je suis ${currentUser.firstName},\nJe vais passé ou j'ai passé un entretien récemment, mais je ne suis pas sûr de ma prestation. Pouvez-vous m’aider à m’améliorer pour les prochains ?\nMerci d'avance`, }, { name: "M'orienter professionnellement", @@ -45,13 +45,7 @@ export const MessagingSuggestions = ({ }, { name: 'Comprendre le marché du travail', - message: `Bonjour, je suis ${ - currentUser.firstName - },\nPourriez-vous m’en dire plus sur les métiers qui recrutent dans mon secteur ${ - currentUser.userProfile?.department - ? `- ${currentUser.userProfile.department}` - : '' - } ? Je veux maximiser mes chances.\nMerci d'avance`, + message: `Bonjour, je suis ${currentUser.firstName},\nPourriez-vous m’en dire plus sur les métiers qui recrutent dans mon secteur ? Je veux maximiser mes chances.\nMerci d'avance`, }, ] as MessagingSuggestionItem[]; }, [currentUser]); From 66cb6b3e6be5d738c5baae93e54df2ee828bf06c Mon Sep 17 00:00:00 2001 From: Guillaume Cauchois Date: Mon, 16 Dec 2024 16:20:00 +0100 Subject: [PATCH 10/11] fix(Dashboard): remove DashboardReadDocumentsCard --- src/components/backoffice/dashboard/Dashboard.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/components/backoffice/dashboard/Dashboard.tsx b/src/components/backoffice/dashboard/Dashboard.tsx index 7c0c54da5..8dda58b3d 100644 --- a/src/components/backoffice/dashboard/Dashboard.tsx +++ b/src/components/backoffice/dashboard/Dashboard.tsx @@ -22,7 +22,6 @@ import { DashboardLinkedUserCard } from './DashboardLinkedUserCard'; import { DashboardMessagingConversation } from './DashboardMessagingConversation'; import { DashboardNextSteps } from './DashboardNextSteps/DashboardNextSteps'; import { DashboardProfileCard } from './DashboardProfileCard'; -import { DashboardReadDocumentsCard } from './DashboardReadDocumentsCard'; import { DashboardRecommendationsCard } from './DashboardRecommendationsCard'; import { DashboardReferentCard } from './DashboardReferentCard'; import { DashboardToolboxCard } from './DashboardToolboxCard'; @@ -51,12 +50,7 @@ export const Dashboard = () => { - {isNormalUser && ( - <> - - - - )} + {isNormalUser && } {isNormalUser && } {isReferer && } From 6154f3bcbb39c0cf33c61f10359a04a9bf49aee4 Mon Sep 17 00:00:00 2001 From: Guillaume Cauchois Date: Mon, 16 Dec 2024 19:17:38 +0100 Subject: [PATCH 11/11] feat(Messaging): add limit on suspicious usage --- src/api/axiosErrors.ts | 9 ++++ .../Notification/Notification.styles.tsx | 44 +++++++++++++------ .../utils/Notification/Notification.tsx | 28 ++++++------ .../Notification/NotificationWrapper.tsx | 2 +- src/constants/styles.ts | 5 +++ src/use-cases/messaging/messaging.saga.ts | 12 ++++- 6 files changed, 70 insertions(+), 30 deletions(-) diff --git a/src/api/axiosErrors.ts b/src/api/axiosErrors.ts index e385b3494..0ebedcc79 100644 --- a/src/api/axiosErrors.ts +++ b/src/api/axiosErrors.ts @@ -51,6 +51,15 @@ export function isEmailAlreadyVerifiedError(error: unknown) { ); } +export function isMessagingDailyConversationLimitReachedError(error: unknown) { + return ( + isAxiosError(error) && + error.response?.status === 429 && + (error.response?.data as { message?: string })?.message === + 'DAILY_CONVERSATION_LIMIT_REACHED' + ); +} + export function isTokenExpiredError(error: unknown) { return ( isAxiosError(error) && diff --git a/src/components/utils/Notification/Notification.styles.tsx b/src/components/utils/Notification/Notification.styles.tsx index 78ae9f67b..b7148120b 100644 --- a/src/components/utils/Notification/Notification.styles.tsx +++ b/src/components/utils/Notification/Notification.styles.tsx @@ -1,10 +1,15 @@ import styled from 'styled-components'; -import { COLORS } from 'src/constants/styles'; +import { BREAKPOINTS, STATUS_COLORS } from 'src/constants/styles'; -export const NOTIF_WIDTH = '600px'; +export const NOTIF_WIDTH = '500px'; export const StyledNotificationWrapper = styled.div``; +const backgroundColor = { + success: STATUS_COLORS.success, + danger: STATUS_COLORS.error, +}; + export const StyledNotificationsContainer = styled.div` display: flex; flex-direction: column; @@ -13,26 +18,37 @@ export const StyledNotificationsContainer = styled.div` position: fixed; right: 0; z-index: 100; + @media screen and (max-width: ${BREAKPOINTS.desktop}px) { + width: 100%; + } `; -const StyledNotification = styled.div` - box-sizing: border-box; +export const StyledNotification = styled.div` + background-color: ${(props) => { + return backgroundColor[props.type]; + }}; + display: flex; width: ${NOTIF_WIDTH}; color: white; - height: 50px; - line-height: 50px; - padding-left: 20px; border-radius: 5px 0 0 5px; - svg { - margin-right: 20px; - height: 25px; + padding: 10px 10px 10px 0; + + @media screen and (max-width: ${BREAKPOINTS.desktop}px) { + width: 100%; } `; -export const StyledSuccessNotification = styled(StyledNotification)` - background-color: ${COLORS.green}; +export const StyledIconContainer = styled.div` + display: flex; + flex-direction: column; + padding: 5px 10px; + justify-content: center; + align-items: center; + flex: 0 0 25px; `; -export const StyledFailedNotification = styled(StyledNotification)` - background-color: ${COLORS.red}; +export const StyledTextContainer = styled.div` + display: flex; + flex-direction: column; + justify-content: center; `; diff --git a/src/components/utils/Notification/Notification.tsx b/src/components/utils/Notification/Notification.tsx index b1b3bdf36..1d3344c72 100644 --- a/src/components/utils/Notification/Notification.tsx +++ b/src/components/utils/Notification/Notification.tsx @@ -1,8 +1,10 @@ import React from 'react'; import { LucidIcon } from '../Icons/LucidIcon'; +import { Text } from '../Text'; import { - StyledFailedNotification, - StyledSuccessNotification, + StyledIconContainer, + StyledNotification, + StyledTextContainer, } from './Notification.styles'; interface NotificationProps { @@ -11,18 +13,16 @@ interface NotificationProps { } export const Notification = ({ type, message }: NotificationProps) => { return ( - <> - {type === 'success' ? ( - - - {message} - - ) : ( - - + + + + + + + {message} - - )} - + + + ); }; diff --git a/src/components/utils/Notification/NotificationWrapper.tsx b/src/components/utils/Notification/NotificationWrapper.tsx index 44324c94e..e7803dd87 100644 --- a/src/components/utils/Notification/NotificationWrapper.tsx +++ b/src/components/utils/Notification/NotificationWrapper.tsx @@ -23,7 +23,7 @@ export const NotificationWrapper = ({ const handleNotification = useCallback(async () => { await asyncTimeout(100); setInProp(true); - await asyncTimeout(3000); + await asyncTimeout(10000); setInProp(false); await asyncTimeout(500); dispatch(notificationsActions.removeNotification({ id })); diff --git a/src/constants/styles.ts b/src/constants/styles.ts index 053cabf94..a6b9811d8 100644 --- a/src/constants/styles.ts +++ b/src/constants/styles.ts @@ -72,6 +72,11 @@ export const COLORS = { darkGreen: '#1F4946', }; +export const STATUS_COLORS = { + success: COLORS.green, + error: COLORS.lightRed, +}; + export const CV_STATUS_COLORS = { none: { border: COLORS.lightGray, diff --git a/src/use-cases/messaging/messaging.saga.ts b/src/use-cases/messaging/messaging.saga.ts index bff11ece4..44def247d 100644 --- a/src/use-cases/messaging/messaging.saga.ts +++ b/src/use-cases/messaging/messaging.saga.ts @@ -1,5 +1,7 @@ import { call, put, select, take, takeLatest } from 'typed-redux-saga'; +import { notificationsActions } from '../notifications'; import { Api } from 'src/api'; +import { isMessagingDailyConversationLimitReachedError } from 'src/api/axiosErrors'; import { ConversationParticipant } from 'src/api/types'; import { slice } from './messaging.slice'; @@ -91,8 +93,16 @@ function* postMessageSagaRequested( isNewConversation: !action.payload.conversationId, }) ); - } catch { + } catch (error: unknown) { yield* put(postMessageFailed()); + if (isMessagingDailyConversationLimitReachedError(error)) { + yield* put( + notificationsActions.addNotification({ + type: 'danger', + message: `Nous sommes désolés, vous avez déjà contacté le maximum de membres aujourd’hui. Laissez le temps aux membres de vous répondre ! Si besoin, vous pourrez en contacter plus à partir de demain !`, + }) + ); + } } }