aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Mo Tarbin <mhed.t91@gmail.com>2024-07-09 17:41:15 -0400
committerLibravatar Mo Tarbin <mhed.t91@gmail.com>2024-07-09 17:41:15 -0400
commit40f1384dfc5ad012b8f47514a07f350141bdf35e (patch)
treee73b81178137747e2d6ece174ed4c6cd704da67d /src
parenta24134f8525373f5707b6c48aa77d3f4aff70799 (diff)
downloaddonetick-frontend-40f1384dfc5ad012b8f47514a07f350141bdf35e.tar.gz
donetick-frontend-40f1384dfc5ad012b8f47514a07f350141bdf35e.tar.bz2
donetick-frontend-40f1384dfc5ad012b8f47514a07f350141bdf35e.zip
Add demo scheduler component for advanced scheduling and automation
Diffstat (limited to 'src')
-rw-r--r--src/views/Landing/DemoAssignee.jsx192
-rw-r--r--src/views/Landing/DemoHistory.jsx95
-rw-r--r--src/views/Landing/DemoMyChore.jsx138
-rw-r--r--src/views/Landing/DemoScheduler.jsx68
-rw-r--r--src/views/Landing/HomeHero.jsx42
-rw-r--r--src/views/Landing/Landing.jsx24
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>