From 6ebf3a2d0ce2b67570aa64b34a9e450f6e28379c Mon Sep 17 00:00:00 2001 From: Justine Okumu Date: Tue, 8 Oct 2024 23:02:14 -0500 Subject: [PATCH] conversation page and tab updates rebased --- public/cm-impact.svg | 9 + public/hompage-conversation.svg | 468 ++++++++++++++++++ public/weekly-goal.svg | 9 + src/const/colors.ts | 4 + src/pages/UserAAuthorizedPages/BadgePage.tsx | 11 + .../ConversationsPage.tsx | 239 +++++++-- src/router/RouteConfig.ts | 1 + src/router/Router.tsx | 6 + src/shared/components/AppBar/CmAppBar.tsx | 14 +- .../components/BorderLinearProgress.tsx | 16 + .../CmBottomTabsNavigation.tsx | 40 +- src/shared/components/CmBadge.tsx | 28 ++ src/shared/components/CmRoundedCard.tsx | 35 ++ src/shared/components/CmTextInput.tsx | 3 +- src/shared/components/CmTextWithIcon.tsx | 21 + src/shared/components/HubPageContent.tsx | 31 ++ src/shared/components/HubPageSection.tsx | 29 ++ 17 files changed, 888 insertions(+), 76 deletions(-) create mode 100644 public/cm-impact.svg create mode 100644 public/hompage-conversation.svg create mode 100644 public/weekly-goal.svg create mode 100644 src/const/colors.ts create mode 100644 src/pages/UserAAuthorizedPages/BadgePage.tsx create mode 100644 src/shared/components/BorderLinearProgress.tsx create mode 100644 src/shared/components/CmBadge.tsx create mode 100644 src/shared/components/CmRoundedCard.tsx create mode 100644 src/shared/components/CmTextWithIcon.tsx create mode 100644 src/shared/components/HubPageContent.tsx create mode 100644 src/shared/components/HubPageSection.tsx diff --git a/public/cm-impact.svg b/public/cm-impact.svg new file mode 100644 index 00000000..30209dd2 --- /dev/null +++ b/public/cm-impact.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/hompage-conversation.svg b/public/hompage-conversation.svg new file mode 100644 index 00000000..98c5ba0f --- /dev/null +++ b/public/hompage-conversation.svg @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/weekly-goal.svg b/public/weekly-goal.svg new file mode 100644 index 00000000..3809282d --- /dev/null +++ b/public/weekly-goal.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/const/colors.ts b/src/const/colors.ts new file mode 100644 index 00000000..fc2e5eab --- /dev/null +++ b/src/const/colors.ts @@ -0,0 +1,4 @@ +export const CM_COLOURS = { + mainDarkGreen: "#07373b", + white: "#ffffff" +} \ No newline at end of file diff --git a/src/pages/UserAAuthorizedPages/BadgePage.tsx b/src/pages/UserAAuthorizedPages/BadgePage.tsx new file mode 100644 index 00000000..e44619ac --- /dev/null +++ b/src/pages/UserAAuthorizedPages/BadgePage.tsx @@ -0,0 +1,11 @@ +import { Page } from "shared/components" + +function BadgePage() { + return ( + +
Badge Page
+
+ ) +} + +export default BadgePage \ No newline at end of file diff --git a/src/pages/UserAAuthorizedPages/ConversationsPage.tsx b/src/pages/UserAAuthorizedPages/ConversationsPage.tsx index 4048abcb..6a8d710b 100644 --- a/src/pages/UserAAuthorizedPages/ConversationsPage.tsx +++ b/src/pages/UserAAuthorizedPages/ConversationsPage.tsx @@ -1,15 +1,34 @@ import { useEffect, useState } from 'react'; -import { useLocation, useSearchParams } from 'react-router-dom'; -import { useMediaQuery } from '@mui/material'; +import { CM_COLOURS } from 'const/colors'; +import HelpIcon from '@mui/icons-material/Help'; -import { CmButton, CmTextInput, CmTypography, Page, PageContent } from 'shared/components'; -import { ConversationsDrawer, CopyLinkModal, useConversationInvite } from 'features/conversations'; +import { CmButton2, CmTextInput, CmTypography, Page } from 'shared/components'; +import { ConversationsDrawer, CopyLinkModal, useConversationInvite, useConversations } from 'features/conversations'; +import { useLocation, useSearchParams } from 'react-router-dom'; +import { BorderLinearProgress } from 'shared/components/BorderLinearProgress'; +import { CmBadge } from 'shared/components/CmBadge'; +import CmGoalCard from 'shared/components/CmRoundedCard'; +import CmRoundedCard from 'shared/components/CmRoundedCard'; +import { CheckCircle, HourglassTopOutlined } from '@mui/icons-material'; +import CmTextWithIcon from 'shared/components/CmTextWithIcon'; function ConversationsPage() { const location = useLocation(); const [searchParams, _] = useSearchParams(); + const badges = Array(4).fill({ name: 'badge name' }); + + const { isLoading, conversations } = useConversations(); - const isSmall = useMediaQuery('(max-width: 960px)'); + const getConversations = (status: 'complete' | 'ongoing') => { + if (status === 'complete') { + return conversations?.filter((conversation) => conversation.state === 5); + } + return conversations?.filter((conversation) => conversation.state !== 5); + }; + + useEffect(() => { + console.log(isLoading); + }, []); // Logic for create link const { inviteToConversation } = useConversationInvite(); @@ -37,48 +56,175 @@ function ConversationsPage() { }, []); return ( - - - Start a conversation - - - Create a personalized link for each person you want to talk to. Then share it, so they can take the quiz, discover your shared values, and pick topics to talk about. - - - - We will send you an email when they agree to share their results with you! - - -
- setFriendsName(e.target.value)} - helperText={friendsName.length > 20 && 'Name must be less than 20 characters'} - style={{ marginTop: 30, marginBottom: 30 }} - /> - - 20} /> - - - +
+ cm conversation image +
+
+
+
+
+ + Create a link to get started! + + +
+
+ + Share this link with a friend so they can take the Values Quiz and select topics to discuss! We will email you when they share their results. + + +
+ setFriendsName(e.target.value)} + helperText={friendsName.length > 20 && 'Name must be less than 20 characters'} + style={{ borderRadius: '10px' }} + /> + + handleSubmit} disabled={friendsName === '' || friendsName.length > 20} /> + +
+
+ setConversationDrawerOpen(false)} /> + + setShowCopyLinkModal(false)} userBName={friendsName} link={link} /> + + + {/* lower section */} +
+
+ + Your Conversations + + + {!conversations || conversations.length == 0 ? ( + + You do not currently have any conversations. Create a quiz link and send it to a friend to get started! + + ) : null} - setConversationDrawerOpen(false)} /> +
+ + Ongoing + - setShowCopyLinkModal(false)} userBName={friendsName} link={link} /> - + {getConversations('ongoing')?.map((conversation) => ( + +
+ + {conversation.userB.name} + +
+ = 0 && conversation.state <= 5 ? : } /> + : } /> + } /> +
+
+
+ ))} +
+ +
+ + Completed + + {getConversations('complete')?.map((conversation) => ( + +
+ + {conversation.userB.name} + +
+ Completed +
+
+
+ ))} +
+ +
+ + Weekly Goal + + +
+ cm weely goals +
+ + Almost there! + + + Reach out to a friend or family member to start talking! + +
+
+
+ + 0/1 Conversations + + +
+
+ +
+ + Want more guidance on how to have great conversations? + + handleSubmit} /> +
+ +
+
+ + Your Climate Badges + + + SEE ALL + +
+
+ {badges.map((badgeInfo) => ( +
+ +
+ ))} +
+
+
+
+
+
); } const styles: { [key: string]: React.CSSProperties } = { + root: { + boxSizing: 'border-box', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'center', + width: '100%', + maxWidth: 640, + margin: '0 auto', + }, + topPageSection: { backgroundColor: CM_COLOURS.mainDarkGreen, padding: '8px 8px 32px 8px' }, + lowerSection: { + background: 'linear-gradient(180deg, #FFFFFF 78.34%, rgba(208, 238, 235, 0.6) 141.86%)', + paddingBottom: '128px', + width: "100%", + }, form: { display: 'flex', flexDirection: 'column', @@ -99,6 +245,21 @@ const styles: { [key: string]: React.CSSProperties } = { width: '100vw', height: 88, }, + imageBanner: { width: '280px', height: '265px', display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', minWidth: '100%' }, + image: { display: 'flex', flexDirection: 'column', justifyContent: 'center' }, + HorizontalDivider: { border: '1px solid #BDFADC', width: '188px', alignSelf: 'center' }, + lowerSectionContainer: { margin: '16px', marginTop: '64px' }, + weeklyGoal: { display: 'flex', flexDirection: 'column', background: '#F5ECFE', boxShadow: '0px 4px 8px 0px #00000040', border: '1px solid #D0EEEB' }, + weeklyGoalTopSection: { display: 'flex', alignItems: 'center' }, + weeklyGoalImage: { width: '105px', height: '100px' }, + weeklyGoalTitle: { padding: '0px', margin: '0px', textAlign: 'left' }, + textLeft: { textAlign: 'left' }, + resourcesArea: { display: 'flex', justifyContent: 'center', flexDirection: 'column', margin: '64px 32px' }, + resourcesButton: { backgroundColor: 'white', border: '1px solid #07373B', boxShadow: '0px 4px 4px 0px #00000040' }, + conversationCardContainer: { display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }, + badgeSectionHeader: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' }, + progressBar: { margin: '16px 0px', backgroundColor: 'white' }, + conversationInputContainer: { display: 'flex', justifyContent: 'center', padding: '16px 16px 0px 16px', flexDirection: 'column' }, }; export default ConversationsPage; diff --git a/src/router/RouteConfig.ts b/src/router/RouteConfig.ts index 7b555580..f849177f 100644 --- a/src/router/RouteConfig.ts +++ b/src/router/RouteConfig.ts @@ -14,6 +14,7 @@ const ROUTES = { USERA_SHARED_FEED_PAGE: '/user-a-shared-feed', SHARED_VALUES_PAGE: '/shared-values', PASSWORD_RESET_PAGE: '/password-reset', + BADGE_PAGE: '/badges', // new userA PRE_QUIZ_PAGE: '/start', diff --git a/src/router/Router.tsx b/src/router/Router.tsx index 6dfd4875..325eb3ca 100644 --- a/src/router/Router.tsx +++ b/src/router/Router.tsx @@ -41,6 +41,7 @@ import UserBNoConsentPage from '../pages/UserBPages/UserBNoConsentPage'; import Error404Page from 'pages/SharedPages/Error404Page'; import AuthorizedPage from 'pages/SharedPages/AuthorizedPage'; import UnauthorizedPage from 'pages/UserAUnauthorizedPages/UnauthorizedPage'; +import BadgePage from 'pages/UserAAuthorizedPages/BadgePage'; const router = createBrowserRouter([ { @@ -135,6 +136,10 @@ const router = createBrowserRouter([ path: ROUTES.PROFILE_PAGE, element: , }, + { + path: `${ROUTES.BADGE_PAGE}`, + element: , + }, ], }, @@ -191,4 +196,5 @@ const router = createBrowserRouter([ }, ]); + export default router; diff --git a/src/shared/components/AppBar/CmAppBar.tsx b/src/shared/components/AppBar/CmAppBar.tsx index 56198437..7be75cb7 100644 --- a/src/shared/components/AppBar/CmAppBar.tsx +++ b/src/shared/components/AppBar/CmAppBar.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import { IconButton, useMediaQuery } from "@mui/material"; -import { Home, EmojiObjects, QuestionAnswer, Announcement, Menu } from "@mui/icons-material"; +import { EmojiObjects, Announcement, Menu, Home, Star } from "@mui/icons-material"; import ROUTES from "router/RouteConfig"; import { useAppSelector } from "store/hooks"; @@ -13,12 +13,12 @@ import { ProfileIcon } from "features/auth/components"; const tabRoutes = [ ROUTES.CLIMATE_FEED_PAGE, ROUTES.SOLUTIONS_FEED_PAGE, - ROUTES.CONVERSATIONS_INTRO_PAGE, + ROUTES.CONVERSATIONS_PAGE, ROUTES.MYTHS_FEED_PAGE, + ROUTES.BADGE_PAGE ]; const conversationRoutes = [ - ROUTES.CONVERSATIONS_INTRO_PAGE, ROUTES.CONVERSATIONS_PAGE, ROUTES.SHARED_VALUES_PAGE, ROUTES.USERA_SHARED_FEED_PAGE, @@ -73,10 +73,11 @@ function CmAppBar({ onShowMenu }: Props) { changeTabHandler(newValue)}> - } label='Home' /> - } label='Actions' /> - } label='Talk' /> + } label='Impact' /> + } label='Solutions' /> + } label='Hub' /> } label='Myths' /> + } label="Badges" /> )} @@ -95,7 +96,6 @@ function CmAppBar({ onShowMenu }: Props) { const styles: { [key: string]: React.CSSProperties } = { root: { backgroundColor: '#07373b', - boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.5)', display: 'flex', justifyContent: 'center', alignItems: 'center', diff --git a/src/shared/components/BorderLinearProgress.tsx b/src/shared/components/BorderLinearProgress.tsx new file mode 100644 index 00000000..e6b2f80c --- /dev/null +++ b/src/shared/components/BorderLinearProgress.tsx @@ -0,0 +1,16 @@ +import { LinearProgress, linearProgressClasses, styled } from "@mui/material"; + +export const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({ + height: 15, + borderRadius: 10, + [`&.${linearProgressClasses.colorPrimary}`]: { + backgroundColor: theme.palette.grey[200], + ...theme.applyStyles('dark', { + backgroundColor: theme.palette.grey[800], + }), + }, + [`& .${linearProgressClasses.bar}`]: { + borderRadius: 5, + backgroundColor: '#FFC727' + }, + })); \ No newline at end of file diff --git a/src/shared/components/BottomTabsNavigation/CmBottomTabsNavigation.tsx b/src/shared/components/BottomTabsNavigation/CmBottomTabsNavigation.tsx index 51870eb9..043ca17e 100644 --- a/src/shared/components/BottomTabsNavigation/CmBottomTabsNavigation.tsx +++ b/src/shared/components/BottomTabsNavigation/CmBottomTabsNavigation.tsx @@ -1,32 +1,22 @@ import { useEffect, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { useMediaQuery } from '@mui/material'; -import { Home, EmojiObjects, QuestionAnswer, Announcement } from '@mui/icons-material'; +import { Home, EmojiObjects, Announcement, Star } from '@mui/icons-material'; import ROUTES from 'router/RouteConfig'; import CmBottomTabs from './CmBottomTabs'; import CmBottomTab from './CmBottomTab'; import { useAppSelector } from 'store/hooks'; -const tabRoutes = [ - ROUTES.CLIMATE_FEED_PAGE, - ROUTES.SOLUTIONS_FEED_PAGE, - ROUTES.CONVERSATIONS_INTRO_PAGE, - ROUTES.MYTHS_FEED_PAGE, -]; +const tabRoutes = [ROUTES.CLIMATE_FEED_PAGE, ROUTES.SOLUTIONS_FEED_PAGE, ROUTES.CONVERSATIONS_PAGE, ROUTES.MYTHS_FEED_PAGE, ROUTES.BADGE_PAGE]; -const conversationRoutes = [ - ROUTES.CONVERSATIONS_INTRO_PAGE, - ROUTES.CONVERSATIONS_PAGE, - ROUTES.SHARED_VALUES_PAGE, - ROUTES.USERA_SHARED_FEED_PAGE, -] +const conversationRoutes = [ROUTES.CONVERSATIONS_PAGE, ROUTES.SHARED_VALUES_PAGE, ROUTES.USERA_SHARED_FEED_PAGE]; function CmBottomTabsNavigation() { const navigate = useNavigate(); const location = useLocation(); - const { isLoggedIn } = useAppSelector(state => state.auth.userA); + const { isLoggedIn } = useAppSelector((state) => state.auth.userA); const isSmall = useMediaQuery('(max-width: 960px)'); const [selectedTab, setSelectedTab] = useState(0); @@ -43,11 +33,11 @@ function CmBottomTabsNavigation() { // Whenever the url changes, update the selected tab useEffect(() => { - const selectedRoute = tabRoutes.findIndex(route => route === location.pathname); + const selectedRoute = tabRoutes.findIndex((route) => route === location.pathname); if (selectedRoute !== -1) { setSelectedTab(selectedRoute); } else { - if (conversationRoutes.filter(route => location.pathname.includes(route)).length > 0) { + if (conversationRoutes.filter((route) => location.pathname.includes(route)).length > 0) { setSelectedTab(2); } else { setSelectedTab(false); @@ -59,19 +49,11 @@ function CmBottomTabsNavigation() { return ( changeTabHandler(newValue)} style={{ backgroundColor: 'white' }}> - } label="Home" /> - } - label="Solutions" - /> - } - label="Talk" - /> - } - label="Myths" - /> + } label="Impact" /> + } label="Solutions" /> + } label="Hub" /> + } label="Myths" /> + } label="Badges" /> ); } diff --git a/src/shared/components/CmBadge.tsx b/src/shared/components/CmBadge.tsx new file mode 100644 index 00000000..2af07cb5 --- /dev/null +++ b/src/shared/components/CmBadge.tsx @@ -0,0 +1,28 @@ + +interface Props { + name: string; +} + + +export const CmBadge = (props: Props) => { + return ( +
+
{/* badge content goes here */}
+ {props.name} +
+ ); +}; + +const styles: { [key: string]: React.CSSProperties } = { + badge: { + width: '64px', + height: '64px', + borderRadius: '50%', + opacity: '0px', + border: '10px solid #D0EEEB', + background: '#D9D9D9', + }, + name: { + textAlign: "center" + } +}; diff --git a/src/shared/components/CmRoundedCard.tsx b/src/shared/components/CmRoundedCard.tsx new file mode 100644 index 00000000..36d540e6 --- /dev/null +++ b/src/shared/components/CmRoundedCard.tsx @@ -0,0 +1,35 @@ +import { Card } from '@mui/material'; +import { ReactNode } from 'react'; + +interface IProps { + children: ReactNode; + conversationStatus?: 'completed' | 'ongoing'; + customStyles?: React.CSSProperties +} + +export default function CmRoundedCard({ children, conversationStatus, customStyles }: IProps) { + + const conversationStyle = + conversationStatus === 'completed' + ? styles.conversationStatusCompleted + : conversationStatus === 'ongoing' + ? styles.conversationStatusOngoing + : {}; + + return {children}; +} + +const styles: { [key: string]: React.CSSProperties } = { + card: { + padding: '0px 16px', + borderRadius: '20px', + }, + conversationStatusCompleted: { + background: 'linear-gradient(90.41deg, #FFFFFF -21.97%, rgba(255, 199, 39, 0.9) 96.54%)', + boxShadow: "0px 4px 8px 0px #00000040", + }, + conversationStatusOngoing: { + boxShadow: '0px 4px 8px 0px #00000040', + background: "#D0EEEB" + }, +}; diff --git a/src/shared/components/CmTextInput.tsx b/src/shared/components/CmTextInput.tsx index d469923a..93c70fb0 100644 --- a/src/shared/components/CmTextInput.tsx +++ b/src/shared/components/CmTextInput.tsx @@ -23,6 +23,7 @@ const CmTextInput = styled((props: Props) => ( fontFamily: 'Nunito', fontWeight: 700, color: '#07373B', + borderRadius: "10px", }, '& .MuiInputBase': { backgroundColor: 'white', @@ -32,7 +33,7 @@ const CmTextInput = styled((props: Props) => ( }, '& .MuiFilledInput': { backgroundColor: 'white', - }, + }, // Underline styles diff --git a/src/shared/components/CmTextWithIcon.tsx b/src/shared/components/CmTextWithIcon.tsx new file mode 100644 index 00000000..2e9372a9 --- /dev/null +++ b/src/shared/components/CmTextWithIcon.tsx @@ -0,0 +1,21 @@ +import CmTypography from './CmTypography'; + +interface ICmTextWithIconProps { + text: string; + icon?: any; + variant?: 'h4' | 'h1' | 'h2' | 'h3' | 'body' | 'body-italics' | 'button' | 'onboarding-button' | 'caption' | 'label' | 'overline'; +} +export default function CmTextWithIcon({ text, icon, variant = 'h4' }: ICmTextWithIconProps) { + return ( + {text} {icon} + ); +} + +const styles: { [key: string]: React.CSSProperties } = { + text: { + paddingRight: "8px", + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + } +}; diff --git a/src/shared/components/HubPageContent.tsx b/src/shared/components/HubPageContent.tsx new file mode 100644 index 00000000..50c336a0 --- /dev/null +++ b/src/shared/components/HubPageContent.tsx @@ -0,0 +1,31 @@ +import PageSection from "./PageSection"; + +interface Props { + sections: [React.ReactNode]; + style?: React.CSSProperties; + } + + function PageContent({ sections, style }: Props) { + return ( +
+ {sections.map(section => {section})} +
+ ); + } + + const styles: { [key: string]: React.CSSProperties } = { + root: { + boxSizing: 'border-box', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'center', + width: '100%', + maxWidth: 640, + margin: '0 auto', + padding: '60px 20px', + }, + }; + + export default PageContent; + \ No newline at end of file diff --git a/src/shared/components/HubPageSection.tsx b/src/shared/components/HubPageSection.tsx new file mode 100644 index 00000000..b7704e13 --- /dev/null +++ b/src/shared/components/HubPageSection.tsx @@ -0,0 +1,29 @@ +interface Props { + children: React.ReactNode; + style?: React.CSSProperties; + } + + function HubPageSection({ children, style }: Props) { + return ( +
+ {children} +
+ ); + } + + const styles: { [key: string]: React.CSSProperties } = { + root: { + boxSizing: 'border-box', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'center', + width: '100%', + maxWidth: 640, + margin: '0 auto', + padding: '60px 20px', + }, + }; + + export default HubPageSection; + \ No newline at end of file