Merge branch 'dev'

This commit is contained in:
Mo Tarbin 2024-07-09 21:21:16 -04:00
commit c684bdb9ec
13 changed files with 729 additions and 135 deletions

1
.env
View file

@ -1 +1,2 @@
VITE_APP_API_URL=http://localhost:2021
VITE_IS_LANDING_DEFAULT=false

View file

@ -20,6 +20,12 @@ import TermsView from '../views/Terms/TermsView'
import TestView from '../views/TestView/Test'
import ThingsHistory from '../views/Things/ThingsHistory'
import ThingsView from '../views/Things/ThingsView'
const getMainRoute = () => {
if (import.meta.env.VITE_IS_LANDING_DEFAULT === 'true') {
return <Landing />
}
return <MyChores />
}
const Router = createBrowserRouter([
{
path: '/',
@ -28,7 +34,7 @@ const Router = createBrowserRouter([
children: [
{
path: '/',
element: <Landing />,
element: getMainRoute(),
},
{
path: '/settings',

View file

@ -0,0 +1,14 @@
import { useEffect, useState } from 'react'
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth)
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth)
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [])
return width
}
export default useWindowWidth

View file

@ -45,7 +45,14 @@ import DateModal from '../Modals/Inputs/DateModal'
import SelectModal from '../Modals/Inputs/SelectModal'
import TextModal from '../Modals/Inputs/TextModal'
import WriteNFCModal from '../Modals/Inputs/WriteNFCModal'
const ChoreCard = ({ chore, performers, onChoreUpdate, onChoreRemove, sx }) => {
const ChoreCard = ({
chore,
performers,
onChoreUpdate,
onChoreRemove,
sx,
viewOnly,
}) => {
const [activeUserId, setActiveUserId] = React.useState(0)
const [isChangeDueDateModalOpen, setIsChangeDueDateModalOpen] =
React.useState(false)
@ -367,6 +374,7 @@ const ChoreCard = ({ chore, performers, onChoreUpdate, onChoreRemove, sx }) => {
</Chip>
<Card
style={viewOnly ? { pointerEvents: 'none' } : {}}
variant='plain'
sx={{
...sx,

View file

@ -3,12 +3,10 @@ import {
Avatar,
Box,
Button,
Chip,
CircularProgress,
Container,
Grid,
List,
ListDivider,
ListItem,
ListItemContent,
ListItemDecorator,
@ -21,6 +19,7 @@ import { Link, useParams } from 'react-router-dom'
import { API_URL } from '../../Config'
import { GetAllCircleMembers } from '../../utils/Fetcher'
import { Fetch } from '../../utils/TokenManager'
import HistoryCard from './HistoryCard'
const ChoreHistory = () => {
const [choreHistory, setChoresHistory] = useState([])
@ -144,25 +143,6 @@ const ChoreHistory = () => {
setHistoryInfo(historyInfo)
}
function formatTimeDifference(startDate, endDate) {
const diffInMinutes = moment(startDate).diff(endDate, 'minutes')
let timeValue = diffInMinutes
let unit = 'minute'
if (diffInMinutes >= 60) {
const diffInHours = moment(startDate).diff(endDate, 'hours')
timeValue = diffInHours
unit = 'hour'
if (diffInHours >= 24) {
const diffInDays = moment(startDate).diff(endDate, 'days')
timeValue = diffInDays
unit = 'day'
}
}
return `${timeValue} ${unit}${timeValue !== 1 ? 's' : ''}`
}
if (isLoading) {
return <CircularProgress /> // Show loading indicator
}
@ -251,89 +231,14 @@ const ChoreHistory = () => {
{/* Chore History List (Updated Style) */}
<List sx={{ p: 0 }}>
{choreHistory.map((chore, index) => (
<>
<ListItem sx={{ gap: 1.5, alignItems: 'flex-start' }}>
{' '}
{/* Adjusted spacing and alignment */}
<ListItemDecorator>
<Avatar sx={{ mr: 1 }}>
{performers
.find(p => p.userId === chore.completedBy)
?.displayName?.charAt(0) || '?'}
</Avatar>
</ListItemDecorator>
<ListItemContent sx={{ my: 0 }}>
{' '}
{/* Removed vertical margin */}
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<Typography level='body1' sx={{ fontWeight: 'md' }}>
{moment(chore.completedAt).format('ddd MM/DD/yyyy HH:mm')}
</Typography>
<Chip>
{chore.dueDate && chore.completedAt > chore.dueDate
? 'Late'
: 'On Time'}
</Chip>
</Box>
<Typography level='body2' color='text.tertiary'>
<Chip>
{
performers.find(p => p.userId === chore.completedBy)
?.displayName
}
</Chip>{' '}
completed
{chore.completedBy !== chore.assignedTo && (
<>
{', '}
assigned to{' '}
<Chip>
{
performers.find(p => p.userId === chore.assignedTo)
?.displayName
}
</Chip>
</>
)}
</Typography>
{chore.dueDate && (
<Typography level='body2' color='text.tertiary'>
Due: {moment(chore.dueDate).format('ddd MM/DD/yyyy')}
</Typography>
)}
{chore.notes && (
<Typography level='body2' color='text.tertiary'>
Note: {chore.notes}
</Typography>
)}
</ListItemContent>
</ListItem>
{index < choreHistory.length - 1 && (
<>
<ListDivider component='li'>
{/* time between two completion: */}
{index < choreHistory.length - 1 &&
choreHistory[index + 1].completedAt && (
<Typography level='body3' color='text.tertiary'>
{formatTimeDifference(
chore.completedAt,
choreHistory[index + 1].completedAt,
)}{' '}
before
</Typography>
)}
</ListDivider>
</>
)}
</>
{choreHistory.map((historyEntry, index) => (
<HistoryCard
historyEntry={historyEntry}
performers={performers}
allHistory={choreHistory}
key={index}
index={index}
/>
))}
</List>
</Box>

View file

@ -0,0 +1,120 @@
import {
Avatar,
Box,
Chip,
ListDivider,
ListItem,
ListItemContent,
ListItemDecorator,
Typography,
} from '@mui/joy'
import moment from 'moment'
const HistoryCard = ({ allHistory, performers, historyEntry, index }) => {
function formatTimeDifference(startDate, endDate) {
const diffInMinutes = moment(startDate).diff(endDate, 'minutes')
let timeValue = diffInMinutes
let unit = 'minute'
if (diffInMinutes >= 60) {
const diffInHours = moment(startDate).diff(endDate, 'hours')
timeValue = diffInHours
unit = 'hour'
if (diffInHours >= 24) {
const diffInDays = moment(startDate).diff(endDate, 'days')
timeValue = diffInDays
unit = 'day'
}
}
return `${timeValue} ${unit}${timeValue !== 1 ? 's' : ''}`
}
return (
<>
<ListItem sx={{ gap: 1.5, alignItems: 'flex-start' }}>
{' '}
{/* Adjusted spacing and alignment */}
<ListItemDecorator>
<Avatar sx={{ mr: 1 }}>
{performers
.find(p => p.userId === historyEntry.completedBy)
?.displayName?.charAt(0) || '?'}
</Avatar>
</ListItemDecorator>
<ListItemContent sx={{ my: 0 }}>
{' '}
{/* Removed vertical margin */}
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<Typography level='body1' sx={{ fontWeight: 'md' }}>
{moment(historyEntry.completedAt).format('ddd MM/DD/yyyy HH:mm')}
</Typography>
<Chip>
{historyEntry.dueDate &&
historyEntry.completedAt > historyEntry.dueDate
? 'Late'
: 'On Time'}
</Chip>
</Box>
<Typography level='body2' color='text.tertiary'>
<Chip>
{
performers.find(p => p.userId === historyEntry.completedBy)
?.displayName
}
</Chip>{' '}
completed
{historyEntry.completedBy !== historyEntry.assignedTo && (
<>
{', '}
assigned to{' '}
<Chip>
{
performers.find(p => p.userId === historyEntry.assignedTo)
?.displayName
}
</Chip>
</>
)}
</Typography>
{historyEntry.dueDate && (
<Typography level='body2' color='text.tertiary'>
Due: {moment(historyEntry.dueDate).format('ddd MM/DD/yyyy')}
</Typography>
)}
{historyEntry.notes && (
<Typography level='body2' color='text.tertiary'>
Note: {historyEntry.notes}
</Typography>
)}
</ListItemContent>
</ListItem>
{index < allHistory.length - 1 && (
<>
<ListDivider component='li'>
{/* time between two completion: */}
{index < allHistory.length - 1 &&
allHistory[index + 1].completedAt && (
<Typography level='body3' color='text.tertiary'>
{formatTimeDifference(
historyEntry.completedAt,
allHistory[index + 1].completedAt,
)}{' '}
before
</Typography>
)}
</ListDivider>
</>
)}
</>
)
}
export default HistoryCard

View file

@ -0,0 +1,192 @@
import {
Box,
Card,
Checkbox,
Grid,
List,
ListItem,
Option,
Select,
Typography,
} from '@mui/joy'
import { useState } from 'react'
const ASSIGN_STRATEGIES = [
'random',
'least_assigned',
'least_completed',
'keep_last_assigned',
]
const DemoAssignee = () => {
const [assignStrategy, setAssignStrategy] = useState('random')
const [assignees, setAssignees] = useState([
{
userId: 3,
id: 3,
displayName: 'Ryan',
},
])
const [assignedTo, setAssignedTo] = useState(3)
const performers = [
{
userId: 1,
id: 1,
displayName: 'Mo',
},
{
userId: 2,
id: 2,
displayName: 'Jiji',
},
{
userId: 3,
id: 3,
displayName: 'Ryan',
},
]
return (
<>
<Grid item xs={12} sm={6} data-aos-create-chore-assignee>
<Box
mt={2}
data-aos-delay={200}
data-aos-anchor='[data-aos-create-chore-assignee]'
data-aos='fade-right'
>
<Typography level='h4'>Assignees :</Typography>
<Typography level='h5'>Who can do this chore?</Typography>
<Card>
<List
orientation='horizontal'
wrap
sx={{
'--List-gap': '8px',
'--ListItem-radius': '20px',
}}
>
{performers?.map(item => (
<ListItem key={item.id}>
<Checkbox
// disabled={index === 0}
checked={assignees.find(a => a.userId == item.id) != null}
onClick={() => {
if (assignees.find(a => a.userId == item.id)) {
setAssignees(
assignees.filter(i => i.userId !== item.id),
)
} else {
setAssignees([...assignees, { userId: item.id }])
}
}}
overlay
disableIcon
variant='soft'
label={item.displayName}
/>
</ListItem>
))}
</List>
</Card>
</Box>
<Box
mt={2}
data-aos-delay={300}
data-aos-anchor='[data-aos-create-chore-assignee]'
data-aos='fade-right'
>
<Typography level='h4'>Assigned :</Typography>
<Typography level='h5'>
Who is assigned the next due chore?
</Typography>
<Select
placeholder={
assignees.length === 0
? 'No Assignees yet can perform this chore'
: 'Select an assignee for this chore'
}
disabled={assignees.length === 0}
value={assignedTo > -1 ? assignedTo : null}
>
{performers
?.filter(p => assignees.find(a => a.userId == p.userId))
.map((item, index) => (
<Option
value={item.id}
key={item.displayName}
onClick={() => {}}
>
{item.displayName}
{/* <Chip size='sm' color='neutral' variant='soft'>
</Chip> */}
</Option>
))}
</Select>
</Box>
<Box
mt={2}
data-aos-delay={400}
data-aos-anchor='[data-aos-create-chore-assignee]'
data-aos='fade-right'
>
<Typography level='h4'>Picking Mode :</Typography>
<Typography level='h5'>
How to pick the next assignee for the following chore?
</Typography>
<Card>
<List
orientation='horizontal'
wrap
sx={{
'--List-gap': '8px',
'--ListItem-radius': '20px',
}}
>
{ASSIGN_STRATEGIES.map((item, idx) => (
<ListItem key={item}>
<Checkbox
// disabled={index === 0}
checked={assignStrategy === item}
onClick={() => setAssignStrategy(item)}
overlay
disableIcon
variant='soft'
label={item
.split('_')
.map(x => x.charAt(0).toUpperCase() + x.slice(1))
.join(' ')}
/>
</ListItem>
))}
</List>
</Card>
</Box>
</Grid>
<Grid item xs={12} sm={6} data-aos-create-chore-section-assignee>
<Card
sx={{
p: 4,
py: 6,
}}
data-aos-delay={200}
data-aos-anchor='[data-aos-create-chore-section-assignee]'
data-aos='fade-left'
>
<Typography level='h3' textAlign='center' sx={{ mt: 2, mb: 4 }}>
Flexible Task Assignment
</Typography>
<Typography level='body-lg' textAlign='center' sx={{ mb: 4 }}>
Whether youre a solo user managing personal tasks or coordinating
chores with others, Donetick provides robust assignment options.
Assign tasks to different people and choose specific rotation
strategies, such as assigning tasks based on who completed the most
or least, randomly rotating assignments, or sticking with the last
assigned person.
</Typography>
</Card>
</Grid>
</>
)
}
export default DemoAssignee

View file

@ -0,0 +1,95 @@
import { Box, Card, Grid, List, Typography } from '@mui/joy'
import moment from 'moment'
import HistoryCard from '../History/HistoryCard'
const DemoHistory = () => {
const allHistory = [
{
id: 32,
choreId: 12,
completedAt: moment().format(),
completedBy: 1,
assignedTo: 1,
notes: null,
dueDate: moment().format(),
},
{
id: 31,
choreId: 12,
completedAt: moment().day(-1).format(),
completedBy: 1,
assignedTo: 1,
notes: 'Need to be replaced with a new one',
dueDate: moment().day(-2).format(),
},
{
id: 31,
choreId: 12,
completedAt: moment().day(-10).format(),
completedBy: 1,
assignedTo: 1,
notes: null,
dueDate: moment().day(-10).format(),
},
]
const performers = [
{
userId: 1,
displayName: 'Ryan',
},
{
userId: 2,
displayName: 'Sarah',
},
]
return (
<>
<Grid item xs={12} sm={6} data-aos-history-list>
<Box sx={{ borderRadius: 'sm', p: 2, boxShadow: 'md' }}>
<List sx={{ p: 0 }}>
{allHistory.map((historyEntry, index) => (
<div
data-aos-delay={100 * index + 200}
data-aos-anchor='[data-aos-history-list]'
data-aos='fade-right'
key={index}
>
<HistoryCard
allHistory={allHistory}
historyEntry={historyEntry}
key={index}
index={index}
performers={performers}
/>
</div>
))}
</List>
</Box>
</Grid>
<Grid item xs={12} sm={6} data-aos-history-demo-section>
<Card
sx={{
p: 4,
py: 6,
}}
data-aos-delay={200}
data-aos-anchor='[data-aos-history-demo-section]'
data-aos='fade-left'
>
<Typography level='h3' textAlign='center' sx={{ mt: 2, mb: 4 }}>
History with a purpose
</Typography>
<Typography level='body-lg' textAlign='center' sx={{ mb: 4 }}>
Keep track of all your chores and tasks with ease. Donetick records
due dates, completion dates, and who completed each task. Any notes
added to tasks are also tracked, providing a complete history for
your reference. Stay organized and informed with detailed task
tracking.
</Typography>
</Card>
</Grid>
</>
)
}
export default DemoHistory

View file

@ -0,0 +1,138 @@
import { Card, Grid, Typography } from '@mui/joy'
import moment from 'moment'
import ChoreCard from '../Chores/ChoreCard'
const DemoMyChore = () => {
const cards = [
{
id: 12,
name: '♻️ Take out recycle ',
frequencyType: 'days_of_the_week',
frequency: 1,
frequencyMetadata:
'{"days":["thursday"],"time":"2024-07-07T22:00:00-04:00"}',
nextDueDate: moment().add(1, 'days').hour(8).minute(0).toISOString(),
isRolling: false,
assignedTo: 1,
},
{
id: 9,
name: '🐜 Spray Pesticide',
frequencyType: 'interval',
frequency: 3,
frequencyMetadata: '{"unit":"months"}',
nextDueDate: moment().subtract(7, 'day').toISOString(),
isRolling: false,
assignedTo: 1,
},
{
id: 6,
name: '🍂 Gutter Cleaning',
frequencyType: 'day_of_the_month',
frequency: 1,
frequencyMetadata: '{"months":["may"]}',
nextDueDate: moment()
.month('may')
.year(moment().year() + 1)
.date(1)
.hour(17)
.minute(0)
.toISOString(),
isRolling: false,
assignedTo: 1,
},
// {
// id: 10,
// name: '💨 Air dust Synology NAS and',
// frequencyType: 'interval',
// frequency: 12,
// frequencyMetadata: '{"unit":"weeks"}',
// nextDueDate: '2024-07-24T17:18:00Z',
// isRolling: false,
// assignedTo: 1,
// },
// {
// id: 8,
// name: '🛁 Deep Cleaning Bathroom',
// frequencyType: 'monthly',
// frequency: 1,
// frequencyMetadata: '{}',
// nextDueDate: '2024-08-04T17:15:00Z',
// isRolling: false,
// assignedTo: 1,
// },
// {
// id: 11,
// name: ' Replace AC Air filter',
// frequencyType: 'adaptive',
// frequency: 1,
// frequencyMetadata: '{"unit":"days"}',
// nextDueDate: moment().add(120, 'days').toISOString(),
// isRolling: false,
// assignedTo: 1,
// },
// {
// id: 6,
// name: '🍂 Gutter Cleaning ',
// frequencyType: 'day_of_the_month',
// frequency: 1,
// frequencyMetadata: '{"months":["may"]}',
// nextDueDate: '2025-05-01T17:00:00Z',
// isRolling: false,
// assignedTo: 1,
// },
// {
// id: 13,
// name: '🚰 Replace Water Filter',
// frequencyType: 'yearly',
// frequency: 1,
// frequencyMetadata: '{}',
// nextDueDate: '2025-07-08T01:00:00Z',
// isRolling: false,
// assignedTo: 1,
// },
]
const users = [{ displayName: 'Me', id: 1 }]
return (
<>
<Grid item xs={12} sm={5} data-aos-first-tasks-list>
{cards.map((card, index) => (
<div
key={index}
data-aos-delay={100 * index + 200}
data-aos-anchor='[data-aos-first-tasks-list]'
data-aos='fade-up'
>
<ChoreCard chore={card} performers={users} viewOnly={true} />
</div>
))}
</Grid>
<Grid item xs={12} sm={7} data-aos-my-chore-demo-section>
<Card
sx={{
p: 4,
py: 6,
}}
data-aos-delay={200}
data-aos-anchor='[data-aos-my-chore-demo-section]'
data-aos='fade-left'
>
<Typography level='h3' textAlign='center' sx={{ mt: 2, mb: 4 }}>
Glance at your task and chores
</Typography>
<Typography level='body-lg' textAlign='center' sx={{ mb: 4 }}>
Main view prioritize tasks due today, followed by overdue ones, and
finally, future tasks or those without due dates. With Donetick, you
can view all the tasks you've created (whether assigned to you or
not) as well as tasks assigned to you by others. Quickly mark them
as done with just one click, ensuring a smooth and efficient task
management experience.
</Typography>
</Card>
</Grid>
</>
)
}
export default DemoMyChore

View file

@ -0,0 +1,68 @@
import { Box, Card, Grid, Typography } from '@mui/joy'
import { useState } from 'react'
import RepeatSection from '../ChoreEdit/RepeatSection'
const DemoScheduler = () => {
const [assignees, setAssignees] = useState([])
const [frequency, setFrequency] = useState(2)
const [frequencyType, setFrequencyType] = useState('weekly')
const [frequencyMetadata, setFrequencyMetadata] = useState({
months: ['may', 'june', 'july'],
})
return (
<>
<Grid item xs={12} sm={5} data-aos-create-chore-scheduler>
<Box
data-aos-delay={300}
data-aos-anchor='[data-aos-create-chore-scheduler]'
data-aos='fade-right'
>
<RepeatSection
frequency={frequency}
onFrequencyUpdate={setFrequency}
frequencyType={frequencyType}
onFrequencyTypeUpdate={setFrequencyType}
frequencyMetadata={frequencyMetadata}
onFrequencyMetadataUpdate={setFrequencyMetadata}
onFrequencyTimeUpdate={t => {}}
frequencyError={null}
allUserThings={[]}
onTriggerUpdate={thingUpdate => {}}
OnTriggerValidate={() => {}}
isAttemptToSave={false}
selectedThing={null}
/>
</Box>
</Grid>
<Grid item xs={12} sm={7} data-aos-create-chore-section-scheduler>
<Card
sx={{
p: 4,
py: 6,
}}
data-aos-delay={200}
data-aos-anchor='[data-aos-create-chore-section-scheduler]'
data-aos='fade-left'
>
<Typography level='h3' textAlign='center' sx={{ mt: 2, mb: 4 }}>
Advanced Scheduling and Automation
</Typography>
<Typography level='body-lg' textAlign='center' sx={{ mb: 4 }}>
Scheduling is a crucial aspect of managing tasks and chores.
Donetick offers basic scheduling options, such as recurring tasks
daily, weekly, or yearly, as well as more customizable schedules
like specific days of the week or month. For those unsure of exact
frequencies, the adaptive scheduling feature averages based on how
often you mark a task as completed. Additionally, Donetick supports
automation by linking tasks with triggers via API. When specific
conditions are met, Doneticks Things feature will automatically
initiate the task, streamlining your workflow.
</Typography>
</Card>
</Grid>
</>
)
}
export default DemoScheduler

View file

@ -4,15 +4,18 @@ import { Button } from '@mui/joy'
import Typography from '@mui/joy/Typography'
import Box from '@mui/material/Box'
import Grid from '@mui/material/Grid'
import React from 'react'
import React, { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import Logo from '@/assets/logo.svg'
import screenShotMyChore from '@/assets/screenshot-my-chore.png'
import { GitHub } from '@mui/icons-material'
import useWindowWidth from '../../hooks/useWindowWidth'
const HomeHero = () => {
const navigate = useNavigate()
const windowWidth = useWindowWidth()
const windowThreshold = 600
const HERO_TEXT_THAT = [
// 'Donetick simplifies the entire process, from scheduling and reminders to automatic task assignment and progress tracking.',
// 'Donetick is the intuitive task and chore management app designed for groups. Take charge of shared responsibilities, automate your workflow, and achieve more together.',
@ -21,7 +24,7 @@ const HomeHero = () => {
const [heroTextIndex, setHeroTextIndex] = React.useState(0)
React.useEffect(() => {
useEffect(() => {
// const intervalId = setInterval(
// () => setHeroTextIndex(index => index + 1),
// 4000, // every 4 seconds
@ -58,6 +61,17 @@ const HomeHero = () => {
>
tick
</span>
<span
style={{
fontSize: 20,
fontWeight: 700,
position: 'relative',
top: 12,
right: 45,
}}
>
Beta
</span>
</Typography>
</Box>
)
@ -162,23 +176,24 @@ const HomeHero = () => {
</Box>
</div>
</Grid>
<Grid item xs={12} md={5}>
<div className='flex justify-center'>
<img
src={screenShotMyChore}
width={'100%'}
style={{
maxWidth: 300,
}}
height={'auto'}
alt='Hero img'
data-aos-delay={100 * 2}
data-aos-anchor='[data-aos-id-hero]'
data-aos='fade-left'
/>
</div>
</Grid>
{windowWidth > windowThreshold && (
<Grid item xs={12} md={5}>
<div className='flex justify-center'>
<img
src={screenShotMyChore}
width={'100%'}
style={{
maxWidth: 300,
}}
height={'auto'}
alt='Hero img'
data-aos-delay={100 * 2}
data-aos-anchor='[data-aos-id-hero]'
data-aos='fade-left'
/>
</div>
</Grid>
)}
</Grid>
)
}

View file

@ -1,18 +1,16 @@
import { Container } from '@mui/joy'
import { Container, Grid } from '@mui/joy'
import AOS from 'aos'
import 'aos/dist/aos.css'
import { useEffect, useState } from 'react'
import { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import DemoAssignee from './DemoAssignee'
import DemoHistory from './DemoHistory'
import DemoMyChore from './DemoMyChore'
import DemoScheduler from './DemoScheduler'
import FeaturesSection from './FeaturesSection'
import HomeHero from './HomeHero'
const Landing = () => {
const Navigate = useNavigate()
const getCurrentUser = () => {
return JSON.parse(localStorage.getItem('user'))
}
const [users, setUsers] = useState([])
const [currentUser, setCurrentUser] = useState(getCurrentUser())
useEffect(() => {
AOS.init({
once: false, // whether animation should happen only once - while scrolling down
@ -22,6 +20,23 @@ const Landing = () => {
return (
<Container className='flex h-full items-center justify-center'>
<HomeHero />
<Grid
overflow={'hidden'}
container
spacing={4}
sx={{
mt: 5,
mb: 5,
// align item vertically:
alignItems: 'center',
}}
>
<DemoMyChore />
<DemoAssignee />
<DemoScheduler />
<DemoHistory />
</Grid>
<FeaturesSection />
{/* <PricingSection /> */}
</Container>

View file

@ -71,12 +71,18 @@ const NavBar = () => {
const location = useLocation()
// if url has /landing then remove the navbar:
if (
['/', '/signup', '/login', '/landing', '/forgot-password'].includes(
['/signup', '/login', '/landing', '/forgot-password'].includes(
location.pathname,
)
) {
return null
}
if (
location.pathname === '/' &&
import.meta.env.VITE_IS_LANDING_DEFAULT === 'true'
) {
return null
}
return (
<nav className='flex gap-2 p-3'>
@ -102,6 +108,17 @@ const NavBar = () => {
tick
</span>
</Typography>
<span
style={{
fontSize: 12,
fontWeight: 700,
position: 'relative',
top: 12,
right: 45,
}}
>
Beta
</span>
</Box>
<Drawer
open={drawerOpen}