From 40f1384dfc5ad012b8f47514a07f350141bdf35e Mon Sep 17 00:00:00 2001 From: Mo Tarbin Date: Tue, 9 Jul 2024 17:41:15 -0400 Subject: Add demo scheduler component for advanced scheduling and automation --- src/views/Landing/DemoAssignee.jsx | 192 ++++++++++++++++++++++++++++++++++++ src/views/Landing/DemoHistory.jsx | 95 ++++++++++++++++++ src/views/Landing/DemoMyChore.jsx | 138 ++++++++++++++++++++++++++ src/views/Landing/DemoScheduler.jsx | 68 +++++++++++++ src/views/Landing/HomeHero.jsx | 42 ++++---- src/views/Landing/Landing.jsx | 24 ++++- 6 files changed, 538 insertions(+), 21 deletions(-) create mode 100644 src/views/Landing/DemoAssignee.jsx create mode 100644 src/views/Landing/DemoHistory.jsx create mode 100644 src/views/Landing/DemoMyChore.jsx create mode 100644 src/views/Landing/DemoScheduler.jsx (limited to 'src/views/Landing') 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 ( + <> + + + Assignees : + Who can do this chore? + + + {performers?.map(item => ( + + 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} + /> + + ))} + + + + + Assigned : + + Who is assigned the next due chore? + + + + + + Picking Mode : + + How to pick the next assignee for the following chore? + + + + + {ASSIGN_STRATEGIES.map((item, idx) => ( + + setAssignStrategy(item)} + overlay + disableIcon + variant='soft' + label={item + .split('_') + .map(x => x.charAt(0).toUpperCase() + x.slice(1)) + .join(' ')} + /> + + ))} + + + + + + + + Flexible Task Assignment + + + 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. + + + + + ) +} + +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 ( + <> + + + + {allHistory.map((historyEntry, index) => ( +
+ +
+ ))} +
+
+
+ + + + History with a purpose + + + 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. + + + + + ) +} +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 ( + <> + + {cards.map((card, index) => ( +
+ +
+ ))} +
+ + + + Glance at your task and chores + + + 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. + + + + + ) +} + +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 ( + <> + + + {}} + frequencyError={null} + allUserThings={[]} + onTriggerUpdate={thingUpdate => {}} + OnTriggerValidate={() => {}} + isAttemptToSave={false} + selectedThing={null} + /> + + + + + + Advanced Scheduling and Automation + + + 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. + + + + + ) +} + +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 = () => { - - -
- Hero img -
-
+ {windowWidth > windowThreshold && ( + +
+ Hero img +
+
+ )} ) } 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 ( + + + + + + + {/* */} -- cgit From e25a6d3be9b9ae443dd3e1cd57a8c5912cc088b2 Mon Sep 17 00:00:00 2001 From: Mo Tarbin Date: Tue, 9 Jul 2024 21:21:00 -0400 Subject: Add VITE_IS_LANDING_DEFAULT flag for conditional rendering of landing page --- src/views/Landing/HomeHero.jsx | 11 +++++++++++ src/views/Landing/Landing.jsx | 7 +------ 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'src/views/Landing') diff --git a/src/views/Landing/HomeHero.jsx b/src/views/Landing/HomeHero.jsx index f01d335..644c9cc 100644 --- a/src/views/Landing/HomeHero.jsx +++ b/src/views/Landing/HomeHero.jsx @@ -61,6 +61,17 @@ const HomeHero = () => { > tick + + Beta + ) diff --git a/src/views/Landing/Landing.jsx b/src/views/Landing/Landing.jsx index fbdefed..a8b650d 100644 --- a/src/views/Landing/Landing.jsx +++ b/src/views/Landing/Landing.jsx @@ -1,7 +1,7 @@ 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' @@ -11,11 +11,6 @@ import FeaturesSection from './FeaturesSection' import HomeHero from './HomeHero' const Landing = () => { const Navigate = useNavigate() - const getCurrentUser = () => { - return JSON.parse(localStorage.getItem('user')) - } - const [currentUser, setCurrentUser] = useState(getCurrentUser()) - useEffect(() => { AOS.init({ once: false, // whether animation should happen only once - while scrolling down -- cgit