From 057c5f7ec871587d2595559bf21f318d0258205d Mon Sep 17 00:00:00 2001 From: Mo Tarbin Date: Thu, 4 Sep 2025 01:49:19 -0400 Subject: [PATCH] feat: Add notification types and enhance color management - Introduced NOTIFICATION_TYPE constants for pre-due, due date, and post-due notifications in Colors.jsx. - Updated HistoryCard.jsx to utilize TASK_COLOR for chip colors based on task status. - Created DemoCalendar.jsx to showcase a visual task calendar with sample chore data. - Enhanced DemoMyChore.jsx to include status for demo tasks. - Added DemoNotificationTemplate.jsx for demonstrating smart notification scheduling. - Revamped FeaturesSection.jsx to reflect updated feature descriptions and icons. - Updated Footer.jsx to link to the correct API reference documentation. - Improved GettingStarted.jsx with new mobile app download options and enhanced layout. - Integrated TabletInstallationSection into Landing.jsx for better user guidance. --- src/components/NotificationTemplate.jsx | 356 +++++++++------ src/utils/Colors.jsx | 5 + src/views/History/HistoryCard.jsx | 12 +- src/views/Landing/DemoCalendar.jsx | 155 +++++++ src/views/Landing/DemoMyChore.jsx | 2 + .../Landing/DemoNotificationTemplate.jsx | 57 +++ src/views/Landing/FeaturesSection.jsx | 173 ++----- src/views/Landing/Footer.jsx | 6 +- src/views/Landing/GettingStarted.jsx | 430 +++++++++++++++--- src/views/Landing/Landing.jsx | 6 +- 10 files changed, 874 insertions(+), 328 deletions(-) create mode 100644 src/views/Landing/DemoCalendar.jsx create mode 100644 src/views/Landing/DemoNotificationTemplate.jsx diff --git a/src/components/NotificationTemplate.jsx b/src/components/NotificationTemplate.jsx index 20386a6..5ff23cc 100644 --- a/src/components/NotificationTemplate.jsx +++ b/src/components/NotificationTemplate.jsx @@ -13,6 +13,7 @@ import Option from '@mui/joy/Option' import Select from '@mui/joy/Select' import Typography from '@mui/joy/Typography' import { useCallback, useEffect, useState } from 'react' +import { NOTIFICATION_TYPE, TASK_COLOR } from '../utils/Colors' const timeUnits = [ { label: 'Mins', value: 'm' }, @@ -307,8 +308,10 @@ const NotificationTemplate = ({ flexDirection: 'column', position: 'relative', height: 90, - bgcolor: 'background.level1', + bgcolor: 'background.surface', borderRadius: 'md', + border: '1px solid', + borderColor: 'neutral.outlinedBorder', p: 2, transition: 'height 0.3s ease', // '&:hover': { @@ -368,11 +371,11 @@ const NotificationTemplate = ({ left: `${percent}%`, transform: 'translateX(-50%)', color: - Number(n.value) < 0 - ? 'primary.600' - : Number(n.value) === 0 - ? 'warning.600' - : 'success.600', + convertToMinutes(n.value, n.unit) < 0 + ? TASK_COLOR.SCHEDULED + : convertToMinutes(n.value, n.unit) === 0 + ? TASK_COLOR.TODAY + : TASK_COLOR.LATE, display: 'flex', flexDirection: 'column', alignItems: 'center', @@ -399,13 +402,6 @@ const NotificationTemplate = ({ } size={'sm'} variant={'solid'} - color={ - Number(n.value) < 0 - ? 'success' - : Number(n.value) === 0 - ? 'warning' - : 'danger' - } sx={{ '--Badge-paddingX': '4px', '--Badge-minHeight': '16px', @@ -413,6 +409,15 @@ const NotificationTemplate = ({ display: 'flex', alignItems: 'center', justifyContent: 'center', + '& .MuiBadge-badge': { + background: + convertToMinutes(n.value, n.unit) < 0 + ? NOTIFICATION_TYPE.PREDUE + : convertToMinutes(n.value, n.unit) === 0 + ? NOTIFICATION_TYPE.DUE_DATE + : NOTIFICATION_TYPE.POSTDUE, + color: 'white', + }, }} > - {/* - Schedule Name - */} - - {/* Template Name Field */} - {/* - - Template Name - - - */} - + {error && ( { + if (Number(value) < 0) { + return { + bgColor: NOTIFICATION_TYPE.PREDUE, + lightBg: `${NOTIFICATION_TYPE.PREDUE}20`, + borderColor: `${NOTIFICATION_TYPE.PREDUE}40`, + textColor: NOTIFICATION_TYPE.PREDUE, + } + } else if (Number(value) === 0) { + return { + bgColor: NOTIFICATION_TYPE.DUE_DATE, + lightBg: `${NOTIFICATION_TYPE.DUE_DATE}20`, + borderColor: `${NOTIFICATION_TYPE.DUE_DATE}40`, + textColor: NOTIFICATION_TYPE.DUE_DATE, + } + } else { + return { + bgColor: NOTIFICATION_TYPE.POSTDUE, + lightBg: `${NOTIFICATION_TYPE.POSTDUE}20`, + borderColor: `${NOTIFICATION_TYPE.POSTDUE}40`, + textColor: NOTIFICATION_TYPE.POSTDUE, + } + } + } + + const colors = getNotificationColors(n.value) + return ( - {/* Empty box to attach badge to */} - + /> + - - - handleChange(idx, 'displayValue', e.target.value) - } + + - - removeNotification(idx)} - disabled={notifications.length === 1} - color={'danger'} - size={'sm'} - sx={{ mr: 1 }} - variant={'soft'} - > - - + + + handleChange(idx, 'displayValue', e.target.value) + } + sx={{ + width: 60, + opacity: uiRep.timing === 'ondue' ? 0.6 : 1, + }} + size={'sm'} + placeholder='0' + /> + + removeNotification(idx)} + disabled={notifications.length === 1} + color={'danger'} + size={'sm'} + variant={'soft'} + sx={{ + transition: 'all 0.2s ease', + '&:hover': { + transform: 'scale(1.1)', + }, + }} + > + + + ) })} - + @@ -596,7 +668,16 @@ const NotificationTemplate = ({ startDecorator={} size={'sm'} variant={'outlined'} - color={'warning'} + sx={{ + borderRadius: 6, + fontWeight: 500, + borderColor: `${NOTIFICATION_TYPE.DUE_DATE}60`, + color: NOTIFICATION_TYPE.DUE_DATE, + '&:hover': { + borderColor: NOTIFICATION_TYPE.DUE_DATE, + background: `${NOTIFICATION_TYPE.DUE_DATE}10`, + }, + }} > Due Alert @@ -606,28 +687,45 @@ const NotificationTemplate = ({ startDecorator={} size={'sm'} variant={'outlined'} - color={'danger'} + sx={{ + borderRadius: 6, + fontWeight: 500, + borderColor: `${NOTIFICATION_TYPE.POSTDUE}60`, + color: NOTIFICATION_TYPE.POSTDUE, + '&:hover': { + borderColor: NOTIFICATION_TYPE.POSTDUE, + background: `${NOTIFICATION_TYPE.POSTDUE}10`, + }, + }} > Follow-up {showSaveDefault && ( - + + + )} {showTimeline && renderTimeline()} diff --git a/src/utils/Colors.jsx b/src/utils/Colors.jsx index 33aa7dc..f82b740 100644 --- a/src/utils/Colors.jsx +++ b/src/utils/Colors.jsx @@ -53,6 +53,11 @@ export const COLORS = { sand: '#d7ccc8', white: '#FFFFFF', } +export const NOTIFICATION_TYPE = { + PREDUE: '#4ec1a2', + DUE_DATE: '#f6ad55', + POSTDUE: '#F03A47', +} export const TASK_COLOR = { COMPLETED: '#4ec1a2', diff --git a/src/views/History/HistoryCard.jsx b/src/views/History/HistoryCard.jsx index bcede5a..68b524e 100644 --- a/src/views/History/HistoryCard.jsx +++ b/src/views/History/HistoryCard.jsx @@ -22,6 +22,7 @@ import { Typography, } from '@mui/joy' import moment from 'moment' +import { TASK_COLOR } from '../../utils/Colors.jsx' const getCompletedChip = historyEntry => { if (historyEntry.status === 0) { @@ -49,7 +50,7 @@ const getCompletedChip = historyEntry => { } > On Time @@ -57,7 +58,12 @@ const getCompletedChip = historyEntry => { ) } else if (performedAt.isBefore(dueDate)) { return ( - }> + } + > Early ) @@ -66,7 +72,7 @@ const getCompletedChip = historyEntry => { } > Late diff --git a/src/views/Landing/DemoCalendar.jsx b/src/views/Landing/DemoCalendar.jsx new file mode 100644 index 0000000..8972f13 --- /dev/null +++ b/src/views/Landing/DemoCalendar.jsx @@ -0,0 +1,155 @@ +import { Card, Grid, Typography } from '@mui/joy' +import moment from 'moment' +import CalendarView from '../components/CalendarView' + +const DemoCalendar = () => { + // Generate sample chore data across different dates + const generateSampleChores = () => { + const today = moment() + const chores = [] + + // High priority tasks + chores.push({ + id: 1, + name: '🧹 Deep Clean Living Room', + priority: 1, + nextDueDate: today.clone().add(2, 'days').hour(10).minute(0).toISOString(), + assignedTo: 1, + }) + + chores.push({ + id: 2, + name: 'πŸš— Car Maintenance Check', + priority: 1, + nextDueDate: today.clone().add(5, 'days').hour(14).minute(30).toISOString(), + assignedTo: 1, + }) + + // Medium priority tasks + chores.push({ + id: 3, + name: '🌱 Water Indoor Plants', + priority: 2, + nextDueDate: today.clone().add(1, 'days').hour(8).minute(0).toISOString(), + assignedTo: 1, + }) + + chores.push({ + id: 4, + name: 'πŸ›’ Weekly Grocery Shopping', + priority: 2, + nextDueDate: today.clone().add(3, 'days').hour(16).minute(0).toISOString(), + assignedTo: 1, + }) + + chores.push({ + id: 5, + name: 'πŸ“§ Organize Email Inbox', + priority: 2, + nextDueDate: today.clone().add(7, 'days').hour(11).minute(0).toISOString(), + assignedTo: 1, + }) + + // Low priority tasks + chores.push({ + id: 6, + name: 'πŸ“š Organize Bookshelf', + priority: 3, + nextDueDate: today.clone().add(4, 'days').hour(15).minute(0).toISOString(), + assignedTo: 1, + }) + + chores.push({ + id: 7, + name: '🎨 Paint Bedroom Wall', + priority: 3, + nextDueDate: today.clone().add(10, 'days').hour(9).minute(0).toISOString(), + assignedTo: 1, + }) + + // Tasks for today + chores.push({ + id: 8, + name: '🍽️ Do Dishes', + priority: 2, + nextDueDate: today.clone().hour(19).minute(0).toISOString(), + assignedTo: 1, + }) + + chores.push({ + id: 9, + name: 'πŸ—‘οΈ Take Out Trash', + priority: 1, + nextDueDate: today.clone().hour(7).minute(30).toISOString(), + assignedTo: 1, + }) + + // Tasks with no priority + chores.push({ + id: 10, + name: '🎡 Practice Guitar', + priority: null, + nextDueDate: today.clone().add(6, 'days').hour(18).minute(0).toISOString(), + assignedTo: 1, + }) + + // Multiple tasks on same day + chores.push({ + id: 11, + name: '🧺 Do Laundry', + priority: 2, + nextDueDate: today.clone().add(2, 'days').hour(12).minute(0).toISOString(), + assignedTo: 1, + }) + + chores.push({ + id: 12, + name: 'πŸƒ Morning Jog', + priority: 3, + nextDueDate: today.clone().add(2, 'days').hour(6).minute(30).toISOString(), + assignedTo: 1, + }) + + return chores + } + + const sampleChores = generateSampleChores() + + return ( + <> + +
+ +
+
+ + + + Visual Task Calendar + + + Get a bird's-eye view of all your tasks with the interactive calendar. + See priority-coded dots for each day, click to view detailed task lists, + and easily track your upcoming responsibilities. The color-coded priority + system helps you focus on what matters most. + + + + + ) +} + +export default DemoCalendar \ No newline at end of file diff --git a/src/views/Landing/DemoMyChore.jsx b/src/views/Landing/DemoMyChore.jsx index 9a09954..e9d72e4 100644 --- a/src/views/Landing/DemoMyChore.jsx +++ b/src/views/Landing/DemoMyChore.jsx @@ -14,6 +14,7 @@ const DemoMyChore = () => { nextDueDate: moment().add(1, 'days').hour(8).minute(0).toISOString(), isRolling: false, assignedTo: 1, + status: 0, }, { id: 9, @@ -24,6 +25,7 @@ const DemoMyChore = () => { nextDueDate: moment().subtract(7, 'day').toISOString(), isRolling: false, assignedTo: 1, + status: 0, }, { id: 6, diff --git a/src/views/Landing/DemoNotificationTemplate.jsx b/src/views/Landing/DemoNotificationTemplate.jsx new file mode 100644 index 0000000..bcb7ffe --- /dev/null +++ b/src/views/Landing/DemoNotificationTemplate.jsx @@ -0,0 +1,57 @@ +import { Card, Grid, Typography } from '@mui/joy' +import NotificationTemplate from '../../components/NotificationTemplate' + +const DemoNotificationTemplate = () => { + const demoNotifications = [ + { value: -3, unit: 'd' }, // 3 days before + { value: 0, unit: 'm' }, // On due + { value: 1, unit: 'd' }, // 1 day after + ] + + const handleNotificationChange = data => { + // Demo handler - doesn't need to do anything + console.log('Demo notification change:', data) + } + + return ( + <> + +
+ +
+
+ + + + Smart Notification Scheduling + + + Set up intelligent reminders for your tasks with flexible timing + options. Get notified before, on, or after due dates with + customizable intervals. + + + + + ) +} + +export default DemoNotificationTemplate diff --git a/src/views/Landing/FeaturesSection.jsx b/src/views/Landing/FeaturesSection.jsx index eb04d8e..182fe31 100644 --- a/src/views/Landing/FeaturesSection.jsx +++ b/src/views/Landing/FeaturesSection.jsx @@ -10,6 +10,7 @@ import { Psychology, Schedule, Security, + Settings, Timer, } from '@mui/icons-material' import { Box, Card, Container, Grid, Typography, useTheme } from '@mui/joy' @@ -19,10 +20,10 @@ const FeaturesSection = () => { const features = [ { - icon: , - title: 'Smart Scheduling', + icon: , + title: 'Natural Language Input', description: - 'Flexible recurring tasks: daily, weekly, monthly, or custom intervals. Choose rolling or fixed schedules and set completion windows to fit any routine.', + 'Add tasks just by typing. Donetick understands dates, priorities, labels. you can have quickest way to add tasks.', }, { icon: , @@ -32,9 +33,21 @@ const FeaturesSection = () => { }, { icon: , - title: 'Motivating Gamification', + title: 'Gamification and Points', description: - 'Earn points, climb leaderboards, and unlock achievements for completing tasks. Make productivity fun and rewarding.', + 'Earn points, climb leaderboards for completing tasks. You can even require admin approval for points!', + }, + { + icon: , + title: 'Visual Calendar View', + description: + 'See all your tasks in a color-coded calendar. Filter by assignee, view daily agendas, and plan with ease.', + }, + { + icon: , + title: 'Smart Scheduling', + description: + 'Flexible recurring tasks: daily, weekly, monthly, or custom intervals. Choose rolling or fixed schedules and set completion windows to fit any routine.', }, { icon: , @@ -42,36 +55,6 @@ const FeaturesSection = () => { description: 'Distribute tasks fairly using smart algorithms: round-robin, least busy, random, or custom rules. No more manual juggling.', }, - { - icon: , - title: 'Insightful Analytics', - description: - 'Track progress, view completion history, and spot trends with clear reports and visualizations. Understand your productivity at a glance.', - }, - { - icon: , - title: 'Advanced Organization', - description: - 'Break down tasks with subtasks, set priorities, add labels and tags, and use templates for quick setup. Stay organized your way.', - }, - { - icon: , - title: 'Smart Notifications', - description: - 'Get timely reminders via email, Telegram, push, or webhooks. Customize alerts so you never miss what matters.', - }, - { - icon: , - title: 'Seamless Integrations', - description: - 'Connect with REST API, webhooks, and automation tools. Import, export, and trigger actions to fit your workflow.', - }, - { - icon: , - title: 'Privacy & Security', - description: - 'Open-source and secure by design. Choose cloud or self-hosting for full control over your data.', - }, { icon: , title: 'Built-in Time Tracking', @@ -79,16 +62,40 @@ const FeaturesSection = () => { 'Track work sessions with a timer, review detailed logs, and analyze productivity patterns for every task.', }, { - icon: , - title: 'Natural Language Input', + icon: , + title: 'Advanced Organization', description: - 'Add tasks just by typing. Our AI understands dates, priorities, labels, and moreβ€”no forms needed.', + 'Break down tasks with subtasks, set priorities, add labels and tags, and use templates for quick setup.', }, { - icon: , - title: 'Visual Calendar View', + icon: , + title: 'Advanced Task Settings', description: - 'See all your tasks in a color-coded calendar. Filter by assignee, view daily agendas, and plan with ease.', + 'Configure task-specific settings like completion windows, custom point values, and require admin approval for tasks.', + }, + { + icon: , + title: 'Insightful Analytics', + description: + 'Track progress, view completion history, and spot trends with clear reports and visualizations.', + }, + { + icon: , + title: 'Smart Notifications', + description: + 'Get timely reminders via Donetick app or other way like Telegram, push, or webhooks.', + }, + { + icon: , + title: 'Seamless Integrations', + description: + 'Connect with REST API, webhooks, and automation tools. Import, export, and trigger actions to fit your workflows.', + }, + { + icon: , + title: 'Privacy & Security', + description: + 'Open-source and transparent. For security, you can secure your account with 2FA.', }, ] @@ -179,33 +186,6 @@ const FeaturesSection = () => { transition: 'opacity 0.4s ease', pointerEvents: 'none', }, - '&:hover': { - transform: { xs: 'translateY(-4px)', sm: 'translateY(-8px)' }, - boxShadow: { - xs: '0 15px 30px rgba(0, 0, 0, 0.08)', - sm: '0 25px 50px rgba(0, 0, 0, 0.1)', - }, - borderColor: 'primary.200', - '&::before': { - transform: 'scaleX(1)', - }, - '&::after': { - opacity: 1, - }, - '& .feature-icon': { - transform: { - xs: 'scale(1.05)', - sm: 'scale(1.1) rotate(5deg)', - }, - background: - 'linear-gradient(135deg, var(--joy-palette-primary-500) 0%, var(--joy-palette-primary-600) 100%)', - color: 'primary.50', - boxShadow: '0 8px 20px rgba(6, 182, 212, 0.3)', - }, - '& .feature-title': { - color: 'primary.600', - }, - }, '@media (max-width: 600px)': { '&:active': { transform: 'scale(0.98)', @@ -286,62 +266,7 @@ const FeaturesSection = () => { mt={{ xs: 8, sm: 10, md: 12 }} data-aos='fade-up' data-aos-duration='800' - > - - - Ready to Transform Your Task Management? - - - Join thousands who have streamlined their workflows with Donetick's - powerful features - - -
+ >
) } diff --git a/src/views/Landing/Footer.jsx b/src/views/Landing/Footer.jsx index c174345..b67c3c9 100644 --- a/src/views/Landing/Footer.jsx +++ b/src/views/Landing/Footer.jsx @@ -21,11 +21,13 @@ const Footer = () => { { label: 'Features', href: '#features' }, { label: 'Demo', href: '#demo' }, { label: 'Getting Started', href: '#getting-started' }, - { label: 'Pricing', href: '/pricing' }, ], resources: [ { label: 'Documentation', href: 'https://docs.donetick.com/' }, - { label: 'API Reference', href: 'https://docs.donetick.com/api' }, + { + label: 'API Reference', + href: 'https://docs.donetick.com/advance-settings/api', + }, { label: 'Discussions', href: 'https://github.com/donetick/donetick/discussions', diff --git a/src/views/Landing/GettingStarted.jsx b/src/views/Landing/GettingStarted.jsx index 0777de2..3ba173b 100644 --- a/src/views/Landing/GettingStarted.jsx +++ b/src/views/Landing/GettingStarted.jsx @@ -1,66 +1,132 @@ import { AddHome, + Android, + Apple, AutoAwesome, Cloud, GitHub, InstallMobile, Storage, } from '@mui/icons-material' -import { Box, Button, Card, Grid, styled, Typography } from '@mui/joy' +import { Box, Button, Card, Container, Grid, Typography } from '@mui/joy' import { useNavigate } from 'react-router-dom' -const IconContainer = styled('div')({ - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - borderRadius: '50%', - minWidth: '60px', - height: '60px', - marginRight: '16px', -}) - -const ButtonContainer = styled('div')({ - display: 'flex', - justifyContent: 'center', - marginTop: 'auto', -}) function StartOptionCard({ icon: Icon, title, description, button, index }) { return ( - {/* Changes are within this div */} - {Icon} + + {Icon} + - + {title} - + {description} - {button} + {button} ) } @@ -70,7 +136,7 @@ const GettingStarted = () => { const information = [ { title: 'Donetick Web', - icon: , + icon: , description: 'The easiest way! Just create account and start using Donetick', button: ( @@ -88,7 +154,7 @@ const GettingStarted = () => { }, { title: 'Selfhosted', - icon: , + icon: , description: 'Download the binary and manage your own Donetick instance', button: (