- Add Cookie Permission component
- Add Filter button instead of chips in mychores view - show except days instead of showing evenything when days.length>4
This commit is contained in:
commit
2d2cf6d378
18 changed files with 508 additions and 175 deletions
3
.env
3
.env
|
@ -1,2 +1,3 @@
|
||||||
VITE_APP_API_URL=http://localhost:2021
|
VITE_APP_API_URL=http://localhost:2021
|
||||||
VITE_IS_LANDING_DEFAULT=false
|
VITE_IS_LANDING_DEFAULT=false
|
||||||
|
VITE_OPENREPLAY_PROJECT_KEY=
|
||||||
|
|
50
package-lock.json
generated
50
package-lock.json
generated
|
@ -1,18 +1,19 @@
|
||||||
{
|
{
|
||||||
"name": "fe-template",
|
"name": "donetick",
|
||||||
"version": "0.1.61",
|
"version": "0.1.72",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "fe-template",
|
"name": "donetick",
|
||||||
"version": "0.1.61",
|
"version": "0.1.72",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.11.3",
|
"@emotion/react": "^11.11.3",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@mui/icons-material": "^5.15.2",
|
"@mui/icons-material": "^5.15.2",
|
||||||
"@mui/joy": "^5.0.0-beta.20",
|
"@mui/joy": "^5.0.0-beta.20",
|
||||||
"@mui/material": "^5.15.2",
|
"@mui/material": "^5.15.2",
|
||||||
|
"@openreplay/tracker": "^14.0.4",
|
||||||
"@tanstack/react-query": "^5.17.0",
|
"@tanstack/react-query": "^5.17.0",
|
||||||
"aos": "^2.3.4",
|
"aos": "^2.3.4",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
|
@ -2481,6 +2482,12 @@
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@medv/finder": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@medv/finder/-/finder-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-JmU7JIBwyL8RAzefvzALT4sP2M0biGk8i2invAgpQmma/QgfsaqoHIvJ7S0YC8n9hUVG8X3Leul2nGa06PvhbQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@mui/base": {
|
"node_modules/@mui/base": {
|
||||||
"version": "5.0.0-beta.29",
|
"version": "5.0.0-beta.29",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.29.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.29.tgz",
|
||||||
|
@ -2839,6 +2846,20 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@openreplay/tracker": {
|
||||||
|
"version": "14.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@openreplay/tracker/-/tracker-14.0.4.tgz",
|
||||||
|
"integrity": "sha512-Mz+MPw9EYbH6tpZ3d1u2yLJsY+MaoBmJX0gQt4HtvGlwJnd7xJvF37xHY8/e3N1Tc7zENsrf7xcpiZXabNKoVQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@medv/finder": "^3.2.0",
|
||||||
|
"error-stack-parser": "^2.0.6",
|
||||||
|
"fflate": "^0.8.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@pkgjs/parseargs": {
|
"node_modules/@pkgjs/parseargs": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||||
|
@ -4747,6 +4768,15 @@
|
||||||
"is-arrayish": "^0.2.1"
|
"is-arrayish": "^0.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/error-stack-parser": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"stackframe": "^1.3.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/es-abstract": {
|
"node_modules/es-abstract": {
|
||||||
"version": "1.22.3",
|
"version": "1.22.3",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz",
|
||||||
|
@ -5327,6 +5357,12 @@
|
||||||
"reusify": "^1.0.4"
|
"reusify": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fflate": {
|
||||||
|
"version": "0.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
||||||
|
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/file-entry-cache": {
|
"node_modules/file-entry-cache": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||||
|
@ -8064,6 +8100,12 @@
|
||||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
|
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
|
||||||
"deprecated": "Please use @jridgewell/sourcemap-codec instead"
|
"deprecated": "Please use @jridgewell/sourcemap-codec instead"
|
||||||
},
|
},
|
||||||
|
"node_modules/stackframe": {
|
||||||
|
"version": "1.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
|
||||||
|
"integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/streamx": {
|
"node_modules/streamx": {
|
||||||
"version": "2.18.0",
|
"version": "2.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "donetick",
|
"name": "donetick",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.65",
|
"version": "0.1.74",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,jsx,ts,tsx}": [
|
"*.{js,jsx,ts,tsx}": [
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
"@mui/icons-material": "^5.15.2",
|
"@mui/icons-material": "^5.15.2",
|
||||||
"@mui/joy": "^5.0.0-beta.20",
|
"@mui/joy": "^5.0.0-beta.20",
|
||||||
"@mui/material": "^5.15.2",
|
"@mui/material": "^5.15.2",
|
||||||
|
"@openreplay/tracker": "^14.0.4",
|
||||||
"@tanstack/react-query": "^5.17.0",
|
"@tanstack/react-query": "^5.17.0",
|
||||||
"aos": "^2.3.4",
|
"aos": "^2.3.4",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
|
|
10
src/App.jsx
10
src/App.jsx
|
@ -1,5 +1,6 @@
|
||||||
import NavBar from '@/views/components/NavBar'
|
import NavBar from '@/views/components/NavBar'
|
||||||
import { Button, Snackbar, Typography, useColorScheme } from '@mui/joy'
|
import { Button, Snackbar, Typography, useColorScheme } from '@mui/joy'
|
||||||
|
import Tracker from '@openreplay/tracker'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { Outlet } from 'react-router-dom'
|
import { Outlet } from 'react-router-dom'
|
||||||
import { useRegisterSW } from 'virtual:pwa-register/react'
|
import { useRegisterSW } from 'virtual:pwa-register/react'
|
||||||
|
@ -19,6 +20,8 @@ const remove = className => {
|
||||||
const intervalMS = 5 * 60 * 1000 // 5 minutes
|
const intervalMS = 5 * 60 * 1000 // 5 minutes
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
startOpenReplay()
|
||||||
|
|
||||||
const { mode, systemMode } = useColorScheme()
|
const { mode, systemMode } = useColorScheme()
|
||||||
const [userProfile, setUserProfile] = useState(null)
|
const [userProfile, setUserProfile] = useState(null)
|
||||||
const [showUpdateSnackbar, setShowUpdateSnackbar] = useState(true)
|
const [showUpdateSnackbar, setShowUpdateSnackbar] = useState(true)
|
||||||
|
@ -115,4 +118,11 @@ function App() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const startOpenReplay = () => {
|
||||||
|
if (!import.meta.env.VITE_OPENREPLAY_PROJECT_KEY) return
|
||||||
|
const tracker = new Tracker({
|
||||||
|
projectKey: import.meta.env.VITE_OPENREPLAY_PROJECT_KEY,
|
||||||
|
})
|
||||||
|
tracker.start()
|
||||||
|
}
|
||||||
export default App
|
export default App
|
||||||
|
|
|
@ -83,6 +83,15 @@ const SkipChore = id => {
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UpdateChoreAssignee = (id, assignee) => {
|
||||||
|
return Fetch(`${API_URL}/chores/${id}/assignee`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: HEADERS(),
|
||||||
|
body: JSON.stringify({ assignee:Number(assignee) }),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const CreateChore = chore => {
|
const CreateChore = chore => {
|
||||||
return Fetch(`${API_URL}/chores/`, {
|
return Fetch(`${API_URL}/chores/`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -306,4 +315,5 @@ export {
|
||||||
UpdateChoreHistory,
|
UpdateChoreHistory,
|
||||||
UpdateThingState,
|
UpdateThingState,
|
||||||
UpdateUserDetails,
|
UpdateUserDetails,
|
||||||
|
UpdateChoreAssignee,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
FormHelperText,
|
FormHelperText,
|
||||||
Input,
|
Input,
|
||||||
Sheet,
|
Sheet,
|
||||||
|
Snackbar,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/joy'
|
} from '@mui/joy'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
@ -25,6 +26,8 @@ const SignupView = () => {
|
||||||
const [emailError, setEmailError] = React.useState('')
|
const [emailError, setEmailError] = React.useState('')
|
||||||
const [displayNameError, setDisplayNameError] = React.useState('')
|
const [displayNameError, setDisplayNameError] = React.useState('')
|
||||||
const [error, setError] = React.useState(null)
|
const [error, setError] = React.useState(null)
|
||||||
|
const [snackbarOpen, setSnackbarOpen] = React.useState(false)
|
||||||
|
const [snackbarMessage, setSnackbarMessage] = React.useState('')
|
||||||
const handleLogin = (username, password) => {
|
const handleLogin = (username, password) => {
|
||||||
login(username, password).then(response => {
|
login(username, password).then(response => {
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
|
@ -39,6 +42,7 @@ const SignupView = () => {
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
console.log('Login failed', response)
|
console.log('Login failed', response)
|
||||||
|
|
||||||
// Navigate('/login')
|
// Navigate('/login')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -101,7 +105,10 @@ const SignupView = () => {
|
||||||
handleLogin(username, password)
|
handleLogin(username, password)
|
||||||
} else {
|
} else {
|
||||||
console.log('Signup failed')
|
console.log('Signup failed')
|
||||||
setError('Signup failed')
|
response.json().then(res => {
|
||||||
|
setError(res.error)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -256,6 +263,14 @@ const SignupView = () => {
|
||||||
</Button>
|
</Button>
|
||||||
</Sheet>
|
</Sheet>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Snackbar
|
||||||
|
open={error !== null}
|
||||||
|
onClose={() => setError(null)}
|
||||||
|
autoHideDuration={5000}
|
||||||
|
message={error}
|
||||||
|
>
|
||||||
|
{error}
|
||||||
|
</Snackbar>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {
|
||||||
CancelScheduleSend,
|
CancelScheduleSend,
|
||||||
Check,
|
Check,
|
||||||
Checklist,
|
Checklist,
|
||||||
|
Edit,
|
||||||
History,
|
History,
|
||||||
PeopleAlt,
|
PeopleAlt,
|
||||||
Person,
|
Person,
|
||||||
|
@ -258,7 +259,7 @@ const ChoreView = () => {
|
||||||
>
|
>
|
||||||
<Grid container spacing={1}>
|
<Grid container spacing={1}>
|
||||||
{infoCards.map((detail, index) => (
|
{infoCards.map((detail, index) => (
|
||||||
<Grid item xs={4} key={index}>
|
<Grid item xs={6} key={index}>
|
||||||
{/* divider between the list items: */}
|
{/* divider between the list items: */}
|
||||||
|
|
||||||
<ListItem key={index}>
|
<ListItem key={index}>
|
||||||
|
@ -411,20 +412,7 @@ const ChoreView = () => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<Box
|
||||||
<Button
|
|
||||||
fullWidth
|
|
||||||
size='lg'
|
|
||||||
onClick={handleTaskCompletion}
|
|
||||||
disabled={isPendingCompletion}
|
|
||||||
color={isPendingCompletion ? 'danger' : 'success'}
|
|
||||||
startDecorator={<Check />}
|
|
||||||
>
|
|
||||||
<Box>Mark as done</Box>
|
|
||||||
</Button>
|
|
||||||
<Divider sx={{ my: 0.5 }}>or</Divider>
|
|
||||||
|
|
||||||
<Box
|
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
@ -433,6 +421,22 @@ const ChoreView = () => {
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Button
|
||||||
|
fullWidth
|
||||||
|
size='lg'
|
||||||
|
onClick={handleTaskCompletion}
|
||||||
|
disabled={isPendingCompletion}
|
||||||
|
color={isPendingCompletion ? 'danger' : 'success'}
|
||||||
|
startDecorator={<Check />}
|
||||||
|
sx={
|
||||||
|
{
|
||||||
|
flex: 4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box>Mark as done</Box>
|
||||||
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
fullWidth
|
fullWidth
|
||||||
size='lg'
|
size='lg'
|
||||||
|
@ -454,9 +458,26 @@ const ChoreView = () => {
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
startDecorator={<SwitchAccessShortcut />}
|
startDecorator={<SwitchAccessShortcut />}
|
||||||
|
sx={
|
||||||
|
{
|
||||||
|
flex: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Box>Skip</Box>
|
<Box>Skip</Box>
|
||||||
</Button>
|
</Button>
|
||||||
|
</Box>
|
||||||
|
<Divider sx={{ my: 0.5 }}>More</Divider>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: 1,
|
||||||
|
alignContent: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
startDecorator={<History />}
|
startDecorator={<History />}
|
||||||
size='lg'
|
size='lg'
|
||||||
|
@ -469,8 +490,21 @@ const ChoreView = () => {
|
||||||
>
|
>
|
||||||
History
|
History
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
|
||||||
|
|
||||||
|
<Button
|
||||||
|
startDecorator={<Edit />}
|
||||||
|
size='lg'
|
||||||
|
color='primary'
|
||||||
|
variant='outlined'
|
||||||
|
fullWidth
|
||||||
|
onClick={() => {
|
||||||
|
navigate(`/chores/${choreId}/edit`)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</Box>
|
||||||
<Snackbar
|
<Snackbar
|
||||||
open={isPendingCompletion}
|
open={isPendingCompletion}
|
||||||
endDecorator={
|
endDecorator={
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {
|
||||||
Check,
|
Check,
|
||||||
Delete,
|
Delete,
|
||||||
Edit,
|
Edit,
|
||||||
HowToReg,
|
|
||||||
KeyboardDoubleArrowUp,
|
KeyboardDoubleArrowUp,
|
||||||
LocalOffer,
|
LocalOffer,
|
||||||
ManageSearch,
|
ManageSearch,
|
||||||
|
@ -39,7 +38,11 @@ import moment from 'moment'
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { API_URL } from '../../Config'
|
import { API_URL } from '../../Config'
|
||||||
import { MarkChoreComplete, SkipChore } from '../../utils/Fetcher'
|
import {
|
||||||
|
MarkChoreComplete,
|
||||||
|
SkipChore,
|
||||||
|
UpdateChoreAssignee,
|
||||||
|
} from '../../utils/Fetcher'
|
||||||
import { Fetch } from '../../utils/TokenManager'
|
import { Fetch } from '../../utils/TokenManager'
|
||||||
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
|
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
|
||||||
import DateModal from '../Modals/Inputs/DateModal'
|
import DateModal from '../Modals/Inputs/DateModal'
|
||||||
|
@ -219,7 +222,14 @@ const ChoreCard = ({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const handleAssigneChange = assigneeId => {
|
const handleAssigneChange = assigneeId => {
|
||||||
// TODO: Implement assignee change
|
UpdateChoreAssignee(chore.id, assigneeId).then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
response.json().then(data => {
|
||||||
|
const newChore = data.res
|
||||||
|
onChoreUpdate(newChore, 'assigned')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const handleCompleteWithNote = note => {
|
const handleCompleteWithNote = note => {
|
||||||
Fetch(`${API_URL}/chores/${chore.id}/do`, {
|
Fetch(`${API_URL}/chores/${chore.id}/do`, {
|
||||||
|
@ -305,8 +315,28 @@ const ChoreCard = ({
|
||||||
return 'Yearly'
|
return 'Yearly'
|
||||||
} else if (chore.frequencyType === 'days_of_the_week') {
|
} else if (chore.frequencyType === 'days_of_the_week') {
|
||||||
let days = JSON.parse(chore.frequencyMetadata).days
|
let days = JSON.parse(chore.frequencyMetadata).days
|
||||||
days = days.map(d => moment().day(d).format('ddd'))
|
if (days.length > 4) {
|
||||||
return days.join(', ')
|
const allDays = [
|
||||||
|
'Sunday',
|
||||||
|
'Monday',
|
||||||
|
'Tuesday',
|
||||||
|
'Wednesday',
|
||||||
|
'Thursday',
|
||||||
|
'Friday',
|
||||||
|
'Saturday',
|
||||||
|
]
|
||||||
|
const selectedDays = days.map(d => moment().day(d).format('dddd'))
|
||||||
|
const notSelectedDay = allDays.filter(
|
||||||
|
day => !selectedDays.includes(day),
|
||||||
|
)
|
||||||
|
const notSelectedShortdays = notSelectedDay.map(d =>
|
||||||
|
moment().day(d).format('ddd'),
|
||||||
|
)
|
||||||
|
return `Daily except ${notSelectedShortdays.join(', ')}`
|
||||||
|
} else {
|
||||||
|
days = days.map(d => moment().day(d).format('ddd'))
|
||||||
|
return days.join(', ')
|
||||||
|
}
|
||||||
} else if (chore.frequencyType === 'day_of_the_month') {
|
} else if (chore.frequencyType === 'day_of_the_month') {
|
||||||
let freqData = JSON.parse(chore.frequencyMetadata)
|
let freqData = JSON.parse(chore.frequencyMetadata)
|
||||||
const months = freqData.months.map(m => moment().month(m).format('MMM'))
|
const months = freqData.months.map(m => moment().month(m).format('MMM'))
|
||||||
|
@ -547,10 +577,6 @@ const ChoreCard = ({
|
||||||
<RecordVoiceOver />
|
<RecordVoiceOver />
|
||||||
Delegate to someone else
|
Delegate to someone else
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem>
|
|
||||||
<HowToReg />
|
|
||||||
Complete as someone else
|
|
||||||
</MenuItem>
|
|
||||||
<Divider />
|
<Divider />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -620,10 +646,13 @@ const ChoreCard = ({
|
||||||
options={performers}
|
options={performers}
|
||||||
displayKey='displayName'
|
displayKey='displayName'
|
||||||
title={`Delegate to someone else`}
|
title={`Delegate to someone else`}
|
||||||
|
placeholder={'Select a performer'}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setIsChangeAssigneeModalOpen(false)
|
setIsChangeAssigneeModalOpen(false)
|
||||||
}}
|
}}
|
||||||
onSave={handleAssigneChange}
|
onSave={selected => {
|
||||||
|
handleAssigneChange(selected.id)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<ConfirmationModal config={confirmModelConfig} />
|
<ConfirmationModal config={confirmModelConfig} />
|
||||||
<TextModal
|
<TextModal
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import { Add, CancelRounded, EditCalendar } from '@mui/icons-material'
|
|
||||||
import {
|
import {
|
||||||
Badge,
|
Add,
|
||||||
|
CancelRounded,
|
||||||
|
EditCalendar,
|
||||||
|
FilterAlt,
|
||||||
|
FilterAltOff,
|
||||||
|
} from '@mui/icons-material'
|
||||||
|
import {
|
||||||
Box,
|
Box,
|
||||||
Checkbox,
|
Chip,
|
||||||
Container,
|
Container,
|
||||||
IconButton,
|
IconButton,
|
||||||
Input,
|
Input,
|
||||||
List,
|
List,
|
||||||
ListItem,
|
|
||||||
Menu,
|
Menu,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Snackbar,
|
Snackbar,
|
||||||
|
@ -192,95 +196,27 @@ const MyChores = () => {
|
||||||
My Chores
|
My Chores
|
||||||
</Typography> */}
|
</Typography> */}
|
||||||
{/* <Sheet> */}
|
{/* <Sheet> */}
|
||||||
<List
|
|
||||||
orientation='horizontal'
|
{/* Search box to filter */}
|
||||||
wrap
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
'--List-gap': '8px',
|
display: 'flex',
|
||||||
'--ListItem-radius': '20px',
|
justifyContent: 'space-between',
|
||||||
'--ListItem-minHeight': '32px',
|
alignContent: 'center',
|
||||||
'--ListItem-gap': '4px',
|
alignItems: 'center',
|
||||||
mt: 0.2,
|
gap: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{['All', 'Overdue', 'Due today', 'Due in week'].map(filter => (
|
|
||||||
<Badge
|
|
||||||
key={filter}
|
|
||||||
anchorOrigin={{
|
|
||||||
vertical: 'top',
|
|
||||||
horizontal: 'right',
|
|
||||||
}}
|
|
||||||
variant='outlined'
|
|
||||||
color={selectedFilter === filter ? 'primary' : 'neutral'}
|
|
||||||
badgeContent={FILTERS[filter](chores).length}
|
|
||||||
badgeInset={'5px'}
|
|
||||||
>
|
|
||||||
<ListItem key={filter}>
|
|
||||||
<Checkbox
|
|
||||||
key={'checkbox' + filter}
|
|
||||||
label={filter}
|
|
||||||
onClick={() => handleSelectedFilter(filter)}
|
|
||||||
checked={filter === selectedFilter}
|
|
||||||
disableIcon
|
|
||||||
overlay
|
|
||||||
size='sm'
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
</Badge>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<ListItem onClick={handleFilterMenuOpen}>
|
|
||||||
<Checkbox key='checkboxAll' label='⋮' disableIcon overlay size='lg' />
|
|
||||||
</ListItem>
|
|
||||||
<Menu
|
|
||||||
ref={menuRef}
|
|
||||||
anchorEl={anchorEl}
|
|
||||||
open={Boolean(anchorEl)}
|
|
||||||
onClose={handleFilterMenuClose}
|
|
||||||
>
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
setFilteredChores(
|
|
||||||
FILTERS['Assigned To Me'](chores, userProfile.id),
|
|
||||||
)
|
|
||||||
setSelectedFilter('Assigned To Me')
|
|
||||||
handleFilterMenuClose()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Assigned to me
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
setFilteredChores(
|
|
||||||
FILTERS['Created By Me'](chores, userProfile.id),
|
|
||||||
)
|
|
||||||
setSelectedFilter('Created By Me')
|
|
||||||
handleFilterMenuClose()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Created by me
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
setFilteredChores(FILTERS['No Due Date'](chores, userProfile.id))
|
|
||||||
setSelectedFilter('No Due Date')
|
|
||||||
handleFilterMenuClose()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
No Due Date
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</List>
|
|
||||||
{/* Search box to filter */}
|
|
||||||
<Box>
|
|
||||||
<Input
|
<Input
|
||||||
placeholder='Search'
|
placeholder='Search'
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
|
fullWidth
|
||||||
sx={{
|
sx={{
|
||||||
mt: 1,
|
mt: 1,
|
||||||
mb: 1,
|
mb: 1,
|
||||||
borderRadius: 20,
|
borderRadius: 24,
|
||||||
// border: '1px solid',
|
// border: '1px solid',
|
||||||
|
height: 24,
|
||||||
borderColor: 'text.disabled',
|
borderColor: 'text.disabled',
|
||||||
padding: 1,
|
padding: 1,
|
||||||
}}
|
}}
|
||||||
|
@ -296,6 +232,73 @@ const MyChores = () => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<IconButton
|
||||||
|
onClick={handleFilterMenuOpen}
|
||||||
|
variant='outlined'
|
||||||
|
color={
|
||||||
|
selectedFilter && selectedFilter != 'All' ? 'primary' : 'neutral'
|
||||||
|
}
|
||||||
|
size='sm'
|
||||||
|
sx={{
|
||||||
|
height: 24,
|
||||||
|
borderRadius: 24,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{selectedFilter && selectedFilter != 'All' ? (
|
||||||
|
<FilterAltOff />
|
||||||
|
) : (
|
||||||
|
<FilterAlt />
|
||||||
|
)}
|
||||||
|
</IconButton>
|
||||||
|
<List
|
||||||
|
orientation='horizontal'
|
||||||
|
wrap
|
||||||
|
sx={{
|
||||||
|
// '--List-gap': '8px',
|
||||||
|
// '--ListItem-radius': '20px',
|
||||||
|
// '--ListItem-minHeight': '32px',
|
||||||
|
// '--ListItem-gap': '4px',
|
||||||
|
mt: 0.2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* <Checkbox
|
||||||
|
key='checkboxAll'
|
||||||
|
label=''
|
||||||
|
disableIcon
|
||||||
|
overlay
|
||||||
|
size='sm'
|
||||||
|
/> */}
|
||||||
|
|
||||||
|
<Menu
|
||||||
|
ref={menuRef}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={Boolean(anchorEl)}
|
||||||
|
onClose={handleFilterMenuClose}
|
||||||
|
>
|
||||||
|
{Object.keys(FILTERS).map(filter => (
|
||||||
|
<MenuItem
|
||||||
|
key={filter}
|
||||||
|
onClick={() => {
|
||||||
|
const filterFunction = FILTERS[filter]
|
||||||
|
const filteredChores =
|
||||||
|
filterFunction.length === 2
|
||||||
|
? filterFunction(chores, userProfile.id)
|
||||||
|
: filterFunction(chores)
|
||||||
|
setFilteredChores(filteredChores)
|
||||||
|
setSelectedFilter(filter)
|
||||||
|
handleFilterMenuClose()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{filter}
|
||||||
|
<Chip color={selectedFilter === filter ? 'primary' : 'neutral'}>
|
||||||
|
{FILTERS[filter].length === 2
|
||||||
|
? FILTERS[filter](chores, userProfile.id).length
|
||||||
|
: FILTERS[filter](chores).length}
|
||||||
|
</Chip>
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Menu>
|
||||||
|
</List>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* </Sheet> */}
|
{/* </Sheet> */}
|
||||||
|
|
40
src/views/Landing/CookiePermissionSnackbar.jsx
Normal file
40
src/views/Landing/CookiePermissionSnackbar.jsx
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { Button, Snackbar } from '@mui/joy'
|
||||||
|
import Cookies from 'js-cookie'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
const CookiePermissionSnackbar = () => {
|
||||||
|
useEffect(() => {
|
||||||
|
const cookiePermission = Cookies.get('cookies_permission')
|
||||||
|
|
||||||
|
if (cookiePermission !== 'true') {
|
||||||
|
setOpen(true)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
const handleClose = () => {
|
||||||
|
Cookies.set('cookies_permission', 'true')
|
||||||
|
setOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Snackbar
|
||||||
|
open={open}
|
||||||
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
|
||||||
|
onClose={(event, reason) => {
|
||||||
|
if (reason === 'clickaway') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Cookies.set('cookies_permission', 'true')
|
||||||
|
handleClose()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
We use cookies to ensure you get the best experience on our website.
|
||||||
|
<Button variant='soft' onClick={handleClose}>
|
||||||
|
Accept
|
||||||
|
</Button>
|
||||||
|
</Snackbar>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CookiePermissionSnackbar
|
|
@ -110,18 +110,6 @@ function FeaturesSection() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container sx={{ textAlign: 'center' }}>
|
<Container sx={{ textAlign: 'center' }}>
|
||||||
<Typography level='h4' mt={2} mb={4}>
|
|
||||||
Donetick is under development
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Container maxWidth={'lg'} sx={{ mb: 8 }}>
|
|
||||||
<Typography level='body-md' color='neutral'>
|
|
||||||
Donetick is beta software. and is still under development. thing may
|
|
||||||
change, break, or disappear at any time. Please use it at your own
|
|
||||||
risk and discretion. I will do my best to keep the service running
|
|
||||||
</Typography>
|
|
||||||
</Container>
|
|
||||||
|
|
||||||
<Typography level='h4' mt={2} mb={4}>
|
<Typography level='h4' mt={2} mb={4}>
|
||||||
Why Donetick?
|
Why Donetick?
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import Box from '@mui/joy/Box'
|
||||||
import Link from '@mui/joy/Link'
|
import Link from '@mui/joy/Link'
|
||||||
import Typography from '@mui/joy/Typography'
|
import Typography from '@mui/joy/Typography'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
import { version } from '../../../package.json'
|
||||||
|
|
||||||
function Footer() {
|
function Footer() {
|
||||||
return (
|
return (
|
||||||
|
@ -47,17 +48,6 @@ function Footer() {
|
||||||
tick✓
|
tick✓
|
||||||
</span>
|
</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: 700,
|
|
||||||
position: 'relative',
|
|
||||||
top: 12,
|
|
||||||
right: 45,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Beta
|
|
||||||
</span>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
|
@ -65,11 +55,11 @@ function Footer() {
|
||||||
Github
|
Github
|
||||||
</Typography>
|
</Typography>
|
||||||
<Link
|
<Link
|
||||||
href='https://github.com/donetick/core'
|
href='https://github.com/donetick/donetick'
|
||||||
level='body2'
|
level='body2'
|
||||||
sx={{ display: 'block' }}
|
sx={{ display: 'block' }}
|
||||||
>
|
>
|
||||||
Core(Backend)
|
Donetick
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href='https://github.com/donetick/frontend'
|
href='https://github.com/donetick/frontend'
|
||||||
|
@ -86,11 +76,18 @@ function Footer() {
|
||||||
Home Assistant Addon
|
Home Assistant Addon
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href='https://github.com/orgs/Donetick/packages'
|
href='https://github.com/orgs/donetick/packages'
|
||||||
level='body2'
|
level='body2'
|
||||||
sx={{ display: 'block' }}
|
sx={{ display: 'block' }}
|
||||||
>
|
>
|
||||||
Packages
|
Docker Images
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href='https://github.com/donetick/donetick/releases'
|
||||||
|
level='body2'
|
||||||
|
sx={{ display: 'block' }}
|
||||||
|
>
|
||||||
|
Releases
|
||||||
</Link>
|
</Link>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
|
@ -107,6 +104,9 @@ function Footer() {
|
||||||
<Link disabled={true} level='body2' sx={{ display: 'block' }}>
|
<Link disabled={true} level='body2' sx={{ display: 'block' }}>
|
||||||
Changelog(soon)
|
Changelog(soon)
|
||||||
</Link>
|
</Link>
|
||||||
|
<Link disabled={true} level='body2' sx={{ display: 'block' }}>
|
||||||
|
V{version}
|
||||||
|
</Link>
|
||||||
</Box>
|
</Box>
|
||||||
{/* <Box>
|
{/* <Box>
|
||||||
<Typography level='body2' fontWeight='bold' mb={1}>
|
<Typography level='body2' fontWeight='bold' mb={1}>
|
||||||
|
|
171
src/views/Landing/GettingStarted.jsx
Normal file
171
src/views/Landing/GettingStarted.jsx
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
import {
|
||||||
|
AddHome,
|
||||||
|
AutoAwesome,
|
||||||
|
Cloud,
|
||||||
|
GitHub,
|
||||||
|
InstallMobile,
|
||||||
|
Storage,
|
||||||
|
} from '@mui/icons-material'
|
||||||
|
import { Box, Button, Card, Grid, styled, 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 (
|
||||||
|
<Card
|
||||||
|
variant='plain'
|
||||||
|
sx={{
|
||||||
|
p: 2,
|
||||||
|
display: 'flex',
|
||||||
|
minHeight: '300px',
|
||||||
|
py: 4,
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
}}
|
||||||
|
data-aos-delay={100 * index}
|
||||||
|
data-aos-anchor='[data-aos-id-getting-started-container]'
|
||||||
|
data-aos='fade-up'
|
||||||
|
>
|
||||||
|
{/* Changes are within this div */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconContainer>{Icon}</IconContainer>
|
||||||
|
|
||||||
|
<Typography level='h4' textAlign={'center'}>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Typography level='body-md' color='neutral' lineHeight={1.6}>
|
||||||
|
{description}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<ButtonContainer>{button}</ButtonContainer>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const GettingStarted = () => {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const information = [
|
||||||
|
{
|
||||||
|
title: 'Donetick Web',
|
||||||
|
icon: <Cloud style={{ fontSize: '48px' }} />,
|
||||||
|
description:
|
||||||
|
'The easiest way! just create account and start using DoneTick',
|
||||||
|
button: (
|
||||||
|
<Button
|
||||||
|
size='lg'
|
||||||
|
fullWidth
|
||||||
|
startDecorator={<AutoAwesome />}
|
||||||
|
onClick={() => {
|
||||||
|
navigate('/my/chores')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Start Now!
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Selfhosted',
|
||||||
|
icon: <Storage style={{ fontSize: '48px' }} />,
|
||||||
|
description: 'Download the binary and manage your own DoneTick instance',
|
||||||
|
button: (
|
||||||
|
<Button
|
||||||
|
size='lg'
|
||||||
|
fullWidth
|
||||||
|
startDecorator={<GitHub />}
|
||||||
|
onClick={() => {
|
||||||
|
window.open(
|
||||||
|
'https://github.com/donetick/donetick/releases',
|
||||||
|
'_blank',
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Github Releases
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Hassio Addon',
|
||||||
|
icon: <AddHome style={{ fontSize: '48px' }} />,
|
||||||
|
description:
|
||||||
|
'have Home Assistant? install DoneTick as a Home Assistant Addon with single click',
|
||||||
|
button: (
|
||||||
|
<Button
|
||||||
|
size='lg'
|
||||||
|
fullWidth
|
||||||
|
startDecorator={<InstallMobile />}
|
||||||
|
onClick={() => {
|
||||||
|
window.open(
|
||||||
|
'https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Fdonetick%2Fhassio-addons',
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Addon
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
alignContent: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
mt: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography level='h4' mt={2} mb={4}>
|
||||||
|
Getting Started
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Box maxWidth={'lg'} sx={{ mb: 8 }}>
|
||||||
|
<Typography level='body-md' color='neutral'>
|
||||||
|
you can start using DoneTick in multiple ways, easiest way is to use
|
||||||
|
Donetick Web and you can start in seconds, or if you are into
|
||||||
|
selfhosting you can download the binary and run it on your own server,
|
||||||
|
or if you are using Home Assistant you can install DoneTick as a Home
|
||||||
|
Assistant Addon
|
||||||
|
</Typography>
|
||||||
|
<div data-aos-id-getting-started-container>
|
||||||
|
<Grid container spacing={4} mt={4}>
|
||||||
|
{information.map((info, index) => (
|
||||||
|
<Grid item xs={12} md={4} key={index}>
|
||||||
|
<StartOptionCard
|
||||||
|
icon={info.icon}
|
||||||
|
title={info.title}
|
||||||
|
description={info.description}
|
||||||
|
button={info.button}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GettingStarted
|
|
@ -61,17 +61,6 @@ const HomeHero = () => {
|
||||||
>
|
>
|
||||||
tick
|
tick
|
||||||
</span>
|
</span>
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: 700,
|
|
||||||
position: 'relative',
|
|
||||||
top: 12,
|
|
||||||
right: 45,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Beta
|
|
||||||
</span>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
@ -167,7 +156,7 @@ const HomeHero = () => {
|
||||||
className='hover:scale-105'
|
className='hover:scale-105'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// new window open to https://github.com/Donetick:
|
// new window open to https://github.com/Donetick:
|
||||||
window.open('https://github.com/donetick', '_blank')
|
window.open('https://github.com/donetick/donetick', '_blank')
|
||||||
}}
|
}}
|
||||||
startDecorator={<GitHub />}
|
startDecorator={<GitHub />}
|
||||||
>
|
>
|
||||||
|
|
|
@ -3,12 +3,14 @@ import AOS from 'aos'
|
||||||
import 'aos/dist/aos.css'
|
import 'aos/dist/aos.css'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import CookiePermissionSnackbar from './CookiePermissionSnackbar'
|
||||||
import DemoAssignee from './DemoAssignee'
|
import DemoAssignee from './DemoAssignee'
|
||||||
import DemoHistory from './DemoHistory'
|
import DemoHistory from './DemoHistory'
|
||||||
import DemoMyChore from './DemoMyChore'
|
import DemoMyChore from './DemoMyChore'
|
||||||
import DemoScheduler from './DemoScheduler'
|
import DemoScheduler from './DemoScheduler'
|
||||||
import FeaturesSection from './FeaturesSection'
|
import FeaturesSection from './FeaturesSection'
|
||||||
import Footer from './Footer'
|
import Footer from './Footer'
|
||||||
|
import GettingStarted from './GettingStarted'
|
||||||
import HomeHero from './HomeHero'
|
import HomeHero from './HomeHero'
|
||||||
const Landing = () => {
|
const Landing = () => {
|
||||||
const Navigate = useNavigate()
|
const Navigate = useNavigate()
|
||||||
|
@ -39,6 +41,8 @@ const Landing = () => {
|
||||||
<DemoHistory />
|
<DemoHistory />
|
||||||
</Grid>
|
</Grid>
|
||||||
<FeaturesSection />
|
<FeaturesSection />
|
||||||
|
<GettingStarted />
|
||||||
|
|
||||||
{/* <PricingSection /> */}
|
{/* <PricingSection /> */}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -49,7 +53,7 @@ const Landing = () => {
|
||||||
mb: 5,
|
mb: 5,
|
||||||
}}
|
}}
|
||||||
></Box>
|
></Box>
|
||||||
|
<CookiePermissionSnackbar />
|
||||||
<Footer />
|
<Footer />
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
} from '@mui/joy'
|
} from '@mui/joy'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
function SelectModal({ isOpen, onClose, onSave, options, title, displayKey }) {
|
function SelectModal({ isOpen, onClose, onSave, options, title, displayKey,placeholder }) {
|
||||||
const [selected, setSelected] = React.useState(null)
|
const [selected, setSelected] = React.useState(null)
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
onSave(options.find(item => item.id === selected))
|
onSave(options.find(item => item.id === selected))
|
||||||
|
@ -20,7 +20,7 @@ function SelectModal({ isOpen, onClose, onSave, options, title, displayKey }) {
|
||||||
<Modal open={isOpen} onClose={onClose}>
|
<Modal open={isOpen} onClose={onClose}>
|
||||||
<ModalDialog>
|
<ModalDialog>
|
||||||
<Typography variant='h4'>{title}</Typography>
|
<Typography variant='h4'>{title}</Typography>
|
||||||
<Select>
|
<Select placeholder={placeholder}>
|
||||||
{options.map((item, index) => (
|
{options.map((item, index) => (
|
||||||
<Option
|
<Option
|
||||||
value={item.id}
|
value={item.id}
|
||||||
|
|
|
@ -30,11 +30,11 @@ const links = [
|
||||||
label: 'Home',
|
label: 'Home',
|
||||||
icon: <HomeOutlined />,
|
icon: <HomeOutlined />,
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
to: '/chores',
|
// to: '/chores',
|
||||||
label: 'Desktop View',
|
// label: 'Desktop View',
|
||||||
icon: <ListAltRounded />,
|
// icon: <ListAltRounded />,
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
to: '/things',
|
to: '/things',
|
||||||
label: 'Things',
|
label: 'Things',
|
||||||
|
@ -114,17 +114,6 @@ const NavBar = () => {
|
||||||
tick✓
|
tick✓
|
||||||
</span>
|
</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: 700,
|
|
||||||
position: 'relative',
|
|
||||||
top: 12,
|
|
||||||
right: 45,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Beta
|
|
||||||
</span>
|
|
||||||
</Box>
|
</Box>
|
||||||
<Drawer
|
<Drawer
|
||||||
open={drawerOpen}
|
open={drawerOpen}
|
||||||
|
|
|
@ -14,7 +14,10 @@ export default defineConfig({
|
||||||
'safari-pinned-tab.svg',
|
'safari-pinned-tab.svg',
|
||||||
'mstile-150x150.png',
|
'mstile-150x150.png',
|
||||||
],
|
],
|
||||||
injectManifest: true,
|
injectManifest: {
|
||||||
|
globPatterns: ['**/*.{js,css,html,png,svg}'],
|
||||||
|
globIgnores: ['index.html'],
|
||||||
|
},
|
||||||
manifest: {
|
manifest: {
|
||||||
name: 'Donetick: Simplify Tasks & Chores, Together.',
|
name: 'Donetick: Simplify Tasks & Chores, Together.',
|
||||||
short_name: 'Donetick',
|
short_name: 'Donetick',
|
||||||
|
@ -55,6 +58,10 @@ export default defineConfig({
|
||||||
background_color: '#ffffff',
|
background_color: '#ffffff',
|
||||||
display: 'standalone',
|
display: 'standalone',
|
||||||
},
|
},
|
||||||
|
workbox: {
|
||||||
|
skipWaiting: true, // Force the waiting service worker to become the active service worker
|
||||||
|
clientsClaim: true, // Take control of uncontrolled clients as soon as the service worker becomes active
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue