move to Donetick Org, First commit frontend

This commit is contained in:
Mo Tarbin 2024-06-30 18:55:39 -04:00
commit 2657469964
105 changed files with 21572 additions and 0 deletions

View file

@ -0,0 +1,139 @@
import {
AutoAwesomeMosaicOutlined,
AutoAwesomeRounded,
CodeRounded,
GroupRounded,
HistoryRounded,
Webhook,
} from '@mui/icons-material'
import Card from '@mui/joy/Card'
import Container from '@mui/joy/Container'
import Typography from '@mui/joy/Typography'
import { styled } from '@mui/system'
const FeatureIcon = styled('div')({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#f0f0f0', // Adjust the background color as needed
borderRadius: '50%',
minWidth: '60px',
height: '60px',
marginRight: '16px',
})
const CardData = [
{
title: 'Open Source & Transparent',
headline: 'Built for the Community',
description:
'Donetick is a community-driven, open-source project. Contribute, customize, and make task management truly yours.',
icon: CodeRounded,
},
{
title: 'Circles: Your Task Hub',
headline: 'Share & Conquer Together',
description:
'Create circles for your family, friends, or team. Easily share tasks and track progress within each group.',
icon: GroupRounded,
},
{
title: 'Track Your Progress',
headline: "See Who's Done What",
description:
'View a history of task completion for each member of your circles. Celebrate successes and stay on top of your goals.',
icon: HistoryRounded,
},
{
title: 'Automated Chore Scheduling',
headline: 'Fully Customizable Recurring Tasks',
description:
'Set up chores to repeat daily, weekly, or monthly. Donetick will automatically assign and track each task for you.',
icon: AutoAwesomeMosaicOutlined,
},
{
title: 'Automated Task Assignment',
headline: 'Share Responsibilities Equally',
description:
'can automatically assigns tasks to each member of your circle. Randomly or based on past completion.',
icon: AutoAwesomeRounded,
},
{
title: 'Integrations & Webhooks',
headline: 'API & 3rd Party Integrations',
description:
'Connect Donetick with your favorite apps and services. Trigger tasks based on events from other platforms.',
icon: Webhook,
},
]
function Feature2({ icon: Icon, title, headline, description, index }) {
return (
<Card
variant='plain'
sx={{ textAlign: 'left', p: 2 }}
data-aos-delay={100 * index}
data-aos-anchor='[data-aos-id-features2-blocks]'
data-aos='fade-up'
>
<div style={{ display: 'flex', alignItems: 'center' }}>
<FeatureIcon>
<Icon
color='primary'
style={{ Width: '30px', height: '30px' }}
stroke={1.5}
/>
</FeatureIcon>
<div>
{/* Changes are within this div */}
<Typography level='h4' mt={1} mb={0.5}>
{title}
</Typography>
<Typography level='body-sm' color='neutral' lineHeight={1.4}>
{headline}
</Typography>
</div>
</div>
<Typography level='body-md' color='neutral' lineHeight={1.6}>
{description}
</Typography>
</Card>
)
}
function FeaturesSection() {
const features = CardData.map((feature, index) => (
<Feature2
icon={feature.icon}
title={feature.title}
headline={feature.headline}
description={feature.description}
index={index}
key={index}
/>
))
return (
<Container sx={{ textAlign: 'center' }}>
<Typography level='h4' mt={2} mb={4}>
Donetick
</Typography>
<Container maxWidth={'lg'} sx={{ mb: 8 }}>
<Typography level='body-md' color='neutral'>
Navigate personal growth with genuine insights, thoughtful privacy,
and actionable steps tailored just for you.
</Typography>
</Container>
<div
className='align-center mt-8 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3'
data-aos-id-features2-blocks
>
{features}
</div>
</Container>
)
}
export default FeaturesSection

View file

@ -0,0 +1,186 @@
/* eslint-disable tailwindcss/no-custom-classname */
// import { StyledButton } from '@/components/styled-button'
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 { 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'
const HomeHero = () => {
const navigate = useNavigate()
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.',
'An open-source, user-friendly app for managing tasks and chores, featuring customizable options to help you and others stay organized',
]
const [heroTextIndex, setHeroTextIndex] = React.useState(0)
React.useEffect(() => {
// const intervalId = setInterval(
// () => setHeroTextIndex(index => index + 1),
// 4000, // every 4 seconds
// )
// return () => clearTimeout(intervalId)
}, [])
const Title = () => (
<Box
sx={{
textAlign: 'center',
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
}}
>
<img src={Logo} width={'100px'} />
<Typography level='h1' fontSize={58} fontWeight={800}>
<span
data-aos-delay={50 * 1}
data-aos-anchor='[data-aos-id-hero]'
data-aos='fade-up'
>
Done
</span>
<span
data-aos-delay={100 * 3}
data-aos-anchor='[data-aos-id-hero]'
data-aos='fade-up'
style={{
color: '#06b6d4',
}}
>
tick
</span>
</Typography>
</Box>
)
const Subtitle = () => (
<Typography
level='h2'
fontWeight={500}
textAlign={'center'}
className='opacity-70'
data-aos-delay={100 * 5}
data-aos-anchor='[data-aos-id-hero]'
data-aos='zoom-in'
>
Simplify Tasks & Chores, Together.
</Typography>
)
const CTAButton = () => (
<Button
data-aos-delay={100 * 2}
data-aos-anchor='[data-aos-id-hero]'
data-aos='fade-up'
variant='solid'
size='lg'
sx={{
py: 1.25,
px: 5,
fontSize: 20,
mt: 2,
borderWidth: 3,
// boxShadow: '0px 0px 24px rgba(81, 230, 221, 0.5)',
transition: 'all 0.20s',
}}
className='hover:scale-105'
onClick={() => {
// if the url is donetick.com then navigate to app.donetick.com/my/chores
// else navigate to /my/chores
if (window.location.hostname === 'donetick.com') {
window.location.href = 'https://app.donetick.com/my/chores'
} else {
navigate('/my/chores')
}
}}
>
Get started
</Button>
)
return (
// <Box
// id='hero'
// className='grid min-h-[90vh] w-full place-items-center px-4 py-12'
// data-aos-id-hero
// >
<Grid container spacing={16} sx={{ py: 12 }}>
<Grid item xs={12} md={7}>
<Title />
<div className='flex flex-col gap-6'>
<Subtitle />
<Typography
level='title-lg'
textAlign={'center'}
fontSize={28}
// textColor={'#06b6d4'}
color='primary'
data-aos-delay={100 * 1}
data-aos-anchor='[data-aos-id-hero]'
data-aos='fade-up'
>
{`"${HERO_TEXT_THAT[heroTextIndex % HERO_TEXT_THAT.length]}"`}
</Typography>
<Box className='flex w-full justify-center'>
<CTAButton />
<Button
data-aos-delay={100 * 2.5}
data-aos-anchor='[data-aos-id-hero]'
data-aos='fade-up'
variant='soft'
size='lg'
sx={{
py: 1.25,
px: 5,
ml: 2,
fontSize: 20,
mt: 2,
borderWidth: 3,
// boxShadow: '0px 0px 24px rgba(81, 230, 221, 0.5)',
transition: 'all 0.20s',
}}
className='hover:scale-105'
onClick={() => {
// new window open to https://github.com/Donetick:
window.open('https://github.com/donetick', '_blank')
}}
startDecorator={<GitHub />}
>
Github
</Button>
</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>
</Grid>
)
}
export default HomeHero

View file

@ -0,0 +1,32 @@
import { Container } from '@mui/joy'
import AOS from 'aos'
import 'aos/dist/aos.css'
import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import FeaturesSection from './FeaturesSection'
import HomeHero from './HomeHero'
import PricingSection from './PricingSection'
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
})
}, [])
return (
<Container className='flex h-full items-center justify-center'>
<HomeHero />
<FeaturesSection />
<PricingSection />
</Container>
)
}
export default Landing

View file

@ -0,0 +1,179 @@
/* eslint-disable react/jsx-key */
import { CheckRounded } from '@mui/icons-material'
import { Box, Button, Card, Container, Typography } from '@mui/joy'
import React from 'react'
import { useNavigate } from 'react-router-dom'
const PricingSection = () => {
const navigate = useNavigate()
const FEATURES_FREE = [
['Create Tasks and Chores', <CheckRounded color='primary' />],
['Limited Task History', <CheckRounded color='primary' />],
['Circle up to two members', <CheckRounded color='primary' />],
]
const FEATURES_PREMIUM = [
['All Basic Features', <CheckRounded color='primary' />],
['Hosted on DoneTick servers', <CheckRounded color='primary' />],
['Up to 8 Circle Members', <CheckRounded color='primary' />],
[
'Notification through Telegram (Discord coming soon)',
<CheckRounded color='primary' />,
],
['Unlimited History', <CheckRounded color='primary' />],
[
'All circle members get the same features as the owner',
<CheckRounded color='primary' />,
],
]
const FEATURES_YEARLY = [
// ['All Basic Features', <CheckRounded color='primary' />],
// ['Up to 8 Circle Members', <CheckRounded color='primary' />],
['Notification through Telegram bot', <CheckRounded color='primary' />],
['Custom Webhook/API Integration', <CheckRounded color='primary' />],
['Unlimited History', <CheckRounded color='primary' />],
['Priority Support', <CheckRounded color='primary' />],
]
const PRICEITEMS = [
{
title: 'Basic',
description:
'Hosted on Donetick servers, supports up to 2 circle members and includes all the features of the free plan.',
price: 0,
previousPrice: 0,
interval: 'month',
discount: false,
features: FEATURES_FREE,
},
{
title: 'Plus',
description:
// 'Supports up to 8 circle members and includes all the features of the Basic plan.',
'Hosted on Donetick servers, supports up to 8 circle members and includes all the features of the Basic plan.',
price: 30.0,
// previousPrice: 76.89,
interval: 'year',
// discount: true,
features: FEATURES_YEARLY,
},
]
return (
<Container
sx={{ textAlign: 'center', mb: 2 }}
maxWidth={'lg'}
id='pricing-tiers'
>
<Typography level='h4' mt={2} mb={2}>
Pricing
</Typography>
<Container maxWidth={'sm'} sx={{ mb: 8 }}>
<Typography level='body-md' color='neutral'>
Choose the plan that works best for you.
</Typography>
</Container>
<div
className='mt-8 grid grid-cols-1 gap-2 sm:grid-cols-1 lg:grid-cols-2'
data-aos-id-pricing
>
{PRICEITEMS.map((pi, index) => (
<Card
key={index}
data-aos-delay={50 * (1 + index)}
data-aos-anchor='[data-aos-id-pricing]'
data-aos='fade-up'
className='hover:bg-white dark:hover:bg-teal-900'
sx={{
textAlign: 'center',
p: 5,
minHeight: 400,
// maxWidth: 400,
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
// when top reach the top change the background color:
'&:hover': {
// backgroundColor: '#FFFFFF',
boxShadow: '0px 0px 20px rgba(0, 0, 0, 0.1)',
},
}}
>
<Box
display='flex'
flexDirection='column'
justifyContent='flex-start' // Updated property
alignItems='center'
>
<Typography level='h2'>{pi.title}</Typography>
<Typography level='body-md'>{pi.description}</Typography>
</Box>
<Box
display='flex'
flexDirection='column'
justifyContent='center'
alignItems='center'
>
<Box
display='flex'
flexDirection='row'
alignItems='baseline'
sx={{ my: 4 }}
>
{pi.discount && (
<Typography
level='h3'
component='span'
sx={{ textDecoration: 'line-through', opacity: 0.5 }}
>
${pi.previousPrice}&nbsp;
</Typography>
)}
<Typography level='h2' component='span'>
${pi.price}
</Typography>
<Typography level='body-md' component='span'>
/ {pi.interval}
</Typography>
</Box>
<Typography level='title-md'>Features</Typography>
{pi.features.map(feature => (
<Typography
startDecorator={feature[1]}
level='body-md'
color='neutral'
lineHeight={1.6}
>
{feature[0]}
</Typography>
))}
{/* Here start the test */}
<div style={{ marginTop: 'auto' }}>
<Button
sx={{ mt: 5 }}
onClick={() => {
navigate('/settings#account')
}}
>
Get Started
</Button>
<Typography
level='body-md'
color='neutral'
lineHeight={1.6}
></Typography>
</div>
</Box>
</Card>
))}
</div>
{/* Here start the test */}
</Container>
)
}
export default PricingSection