diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/views/Landing/DemoAssignee.jsx | 192 | ||||
-rw-r--r-- | src/views/Landing/DemoHistory.jsx | 95 | ||||
-rw-r--r-- | src/views/Landing/DemoMyChore.jsx | 138 | ||||
-rw-r--r-- | src/views/Landing/DemoScheduler.jsx | 68 | ||||
-rw-r--r-- | src/views/Landing/HomeHero.jsx | 42 | ||||
-rw-r--r-- | src/views/Landing/Landing.jsx | 24 |
6 files changed, 538 insertions, 21 deletions
diff --git a/src/views/Landing/DemoAssignee.jsx b/src/views/Landing/DemoAssignee.jsx new file mode 100644 index 0000000..5064cf0 --- /dev/null +++ b/src/views/Landing/DemoAssignee.jsx @@ -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 you’re 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 diff --git a/src/views/Landing/DemoHistory.jsx b/src/views/Landing/DemoHistory.jsx new file mode 100644 index 0000000..2c713f1 --- /dev/null +++ b/src/views/Landing/DemoHistory.jsx @@ -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 diff --git a/src/views/Landing/DemoMyChore.jsx b/src/views/Landing/DemoMyChore.jsx new file mode 100644 index 0000000..be56cae --- /dev/null +++ b/src/views/Landing/DemoMyChore.jsx @@ -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 diff --git a/src/views/Landing/DemoScheduler.jsx b/src/views/Landing/DemoScheduler.jsx new file mode 100644 index 0000000..5e34adb --- /dev/null +++ b/src/views/Landing/DemoScheduler.jsx @@ -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, Donetick’s Things feature will automatically + initiate the task, streamlining your workflow. + </Typography> + </Card> + </Grid> + </> + ) +} + +export default DemoScheduler diff --git a/src/views/Landing/HomeHero.jsx b/src/views/Landing/HomeHero.jsx index a96374a..f01d335 100644 --- a/src/views/Landing/HomeHero.jsx +++ b/src/views/Landing/HomeHero.jsx @@ -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 @@ -162,23 +165,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> ) } diff --git a/src/views/Landing/Landing.jsx b/src/views/Landing/Landing.jsx index 6d3a1ce..fbdefed 100644 --- a/src/views/Landing/Landing.jsx +++ b/src/views/Landing/Landing.jsx @@ -1,8 +1,12 @@ -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 { 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 = () => { @@ -10,7 +14,6 @@ const Landing = () => { const getCurrentUser = () => { return JSON.parse(localStorage.getItem('user')) } - const [users, setUsers] = useState([]) const [currentUser, setCurrentUser] = useState(getCurrentUser()) useEffect(() => { @@ -22,6 +25,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> |