Make label Clickable
Fix changing URL for selfhosted Update styling for calendar and thingview
This commit is contained in:
parent
4527b229ed
commit
ba149d0e96
10 changed files with 171 additions and 166 deletions
|
@ -25,6 +25,7 @@ class ApiManager {
|
||||||
}
|
}
|
||||||
updateApiURL(url) {
|
updateApiURL(url) {
|
||||||
this.customServerURL = url
|
this.customServerURL = url
|
||||||
|
this.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,18 @@
|
||||||
import GoogleIcon from '@mui/icons-material/Google'
|
import { Preferences } from '@capacitor/preferences'
|
||||||
import {
|
import {
|
||||||
Avatar,
|
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Container,
|
Container,
|
||||||
Divider,
|
|
||||||
IconButton,
|
|
||||||
Input,
|
Input,
|
||||||
Sheet,
|
Sheet,
|
||||||
Snackbar,
|
Snackbar,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/joy'
|
} from '@mui/joy'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { LoginSocialGoogle } from 'reactjs-social-login'
|
|
||||||
import { API_URL, GOOGLE_CLIENT_ID, REDIRECT_URL } from '../../Config'
|
|
||||||
import Logo from '../../Logo'
|
|
||||||
import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
|
|
||||||
import { Capacitor } from '@capacitor/core'
|
|
||||||
import { Settings } from '@mui/icons-material'
|
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { Preferences } from '@capacitor/preferences'
|
import { API_URL } from '../../Config'
|
||||||
|
import Logo from '../../Logo'
|
||||||
|
import { apiManager } from '../../utils/TokenManager'
|
||||||
|
|
||||||
const LoginSettings = () => {
|
const LoginSettings = () => {
|
||||||
const [error, setError] = React.useState(null)
|
const [error, setError] = React.useState(null)
|
||||||
const Navigate = useNavigate()
|
const Navigate = useNavigate()
|
||||||
|
@ -30,7 +20,7 @@ const LoginSettings = () => {
|
||||||
const [serverURL, setServerURL] = React.useState('')
|
const [serverURL, setServerURL] = React.useState('')
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
Preferences.get({ key: 'customServerUrl' }).then((result) => {
|
Preferences.get({ key: 'customServerUrl' }).then(result => {
|
||||||
setServerURL(result.value || API_URL)
|
setServerURL(result.value || API_URL)
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
@ -40,11 +30,7 @@ const LoginSettings = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container component='main' maxWidth='xs'>
|
||||||
component='main'
|
|
||||||
maxWidth='xs'
|
|
||||||
|
|
||||||
>
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
marginTop: 4,
|
marginTop: 4,
|
||||||
|
@ -67,103 +53,101 @@ const LoginSettings = () => {
|
||||||
boxShadow: 'md',
|
boxShadow: 'md',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Logo />
|
<Logo />
|
||||||
|
|
||||||
<Typography level='h2'>
|
<Typography level='h2'>
|
||||||
Done
|
Done
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color: '#06b6d4',
|
color: '#06b6d4',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
tick
|
tick
|
||||||
</span>
|
</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
|
<Typography level='body2' alignSelf={'start'} mt={4}>
|
||||||
|
Server URL
|
||||||
|
</Typography>
|
||||||
|
<Input
|
||||||
|
margin='normal'
|
||||||
|
required
|
||||||
|
fullWidth
|
||||||
|
id='serverURL'
|
||||||
|
name='serverURL'
|
||||||
|
autoFocus
|
||||||
|
value={serverURL}
|
||||||
|
onChange={e => {
|
||||||
|
setServerURL(e.target.value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Typography mt={1} level='body-xs'>
|
||||||
|
Change the server URL to connect to a different server, such as your
|
||||||
|
own self-hosted Donetick server.
|
||||||
<Typography level='body2' alignSelf={'start'} mt={4} >
|
</Typography>
|
||||||
Server URL
|
<Typography mt={1} level='body-xs'>
|
||||||
</Typography>
|
Please ensure to include the protocol (http:// or https://) and the
|
||||||
<Input
|
port number if necessary (default Donetick port is 2021).
|
||||||
margin='normal'
|
</Typography>
|
||||||
required
|
<Button
|
||||||
fullWidth
|
fullWidth
|
||||||
id='serverURL'
|
size='lg'
|
||||||
name='serverURL'
|
variant='solid'
|
||||||
autoFocus
|
sx={{
|
||||||
value={serverURL}
|
width: '100%',
|
||||||
onChange={e => {
|
mt: 3,
|
||||||
setServerURL(e.target.value)
|
mb: 2,
|
||||||
}}
|
border: 'moccasin',
|
||||||
/>
|
borderRadius: '8px',
|
||||||
|
}}
|
||||||
<Typography mt={1} level='body-xs'>
|
onClick={() => {
|
||||||
Change the server URL to connect to a different server, such as your own self-hosted Donetick server.
|
if (serverURL === '') {
|
||||||
</Typography>
|
Preferences.set({
|
||||||
<Typography mt={1} level='body-xs'>
|
key: 'customServerUrl',
|
||||||
Please ensure to include the protocol (http:// or https://) and the port number if necessary (default Donetick port is 2021).
|
value: API_URL,
|
||||||
</Typography>
|
}).then(() => {
|
||||||
<Button
|
Navigate('/login')
|
||||||
fullWidth
|
})
|
||||||
size='lg'
|
return
|
||||||
variant='solid'
|
|
||||||
sx={{
|
|
||||||
width: '100%',
|
|
||||||
mt: 3,
|
|
||||||
mb: 2,
|
|
||||||
border: 'moccasin',
|
|
||||||
borderRadius: '8px',
|
|
||||||
}}
|
|
||||||
|
|
||||||
onClick={() => {
|
|
||||||
if (serverURL === '') {
|
|
||||||
Preferences.set({ key: 'customServerUrl', value: API_URL }).then(() => {
|
|
||||||
Navigate('/login')
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!isValidServerURL()){
|
|
||||||
setError('Invalid server URL')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Preferences.set({ key: 'customServerUrl', value: serverURL }).then(() => {
|
|
||||||
Navigate('/login')
|
|
||||||
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!isValidServerURL()) {
|
||||||
>
|
setError('Invalid server URL')
|
||||||
Save
|
return
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
fullWidth
|
|
||||||
size='lg'
|
|
||||||
variant='soft'
|
|
||||||
color='danger'
|
|
||||||
|
|
||||||
sx={{
|
|
||||||
width: '100%',
|
|
||||||
|
|
||||||
mb: 2,
|
|
||||||
border: 'moccasin',
|
|
||||||
borderRadius: '8px',
|
|
||||||
}}
|
|
||||||
|
|
||||||
onClick={() => {
|
|
||||||
Preferences.set({ key: 'customServerUrl', value: API_URL }).then(() => {
|
|
||||||
Navigate('/login')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Preferences.set({
|
||||||
|
key: 'customServerUrl',
|
||||||
|
value: serverURL,
|
||||||
|
}).then(() => {
|
||||||
|
apiManager.updateApiURL(serverURL + '/api/v1')
|
||||||
|
Navigate('/login')
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
fullWidth
|
||||||
|
size='lg'
|
||||||
|
variant='soft'
|
||||||
|
color='danger'
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
|
||||||
>
|
mb: 2,
|
||||||
Cancel and Reset
|
border: 'moccasin',
|
||||||
</Button>
|
borderRadius: '8px',
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
Preferences.set({ key: 'customServerUrl', value: API_URL }).then(
|
||||||
|
() => {
|
||||||
|
Navigate('/login')
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel and Reset
|
||||||
|
</Button>
|
||||||
</Sheet>
|
</Sheet>
|
||||||
</Box>
|
</Box>
|
||||||
<Snackbar
|
<Snackbar
|
||||||
|
|
|
@ -140,27 +140,23 @@ const LoginView = () => {
|
||||||
boxShadow: 'md',
|
boxShadow: 'md',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconButton
|
{Capacitor.isNativePlatform() && (
|
||||||
// on top right of the screen:
|
<IconButton
|
||||||
sx={{
|
// on top right of the screen:
|
||||||
position: 'absolute',
|
sx={{
|
||||||
top: 2,
|
position: 'absolute',
|
||||||
right: 2,
|
top: 2,
|
||||||
color: 'black',
|
right: 2,
|
||||||
}}
|
color: 'black',
|
||||||
onClick={() => {
|
}}
|
||||||
Navigate('/login/settings')
|
onClick={() => {
|
||||||
}}
|
Navigate('/login/settings')
|
||||||
>
|
}}
|
||||||
{' '}
|
>
|
||||||
<Settings />
|
{' '}
|
||||||
</IconButton>
|
<Settings />
|
||||||
{/* <img
|
</IconButton>
|
||||||
src='/src/assets/logo.svg'
|
)}
|
||||||
alt='logo'
|
|
||||||
width='128px'
|
|
||||||
height='128px'
|
|
||||||
/> */}
|
|
||||||
<Logo />
|
<Logo />
|
||||||
|
|
||||||
<Typography level='h2'>
|
<Typography level='h2'>
|
||||||
|
|
|
@ -435,6 +435,7 @@ const ChoreView = () => {
|
||||||
sx={{
|
sx={{
|
||||||
p: 2,
|
p: 2,
|
||||||
borderRadius: 'lg',
|
borderRadius: 'lg',
|
||||||
|
mb: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
|
|
@ -194,7 +194,7 @@ const ChoreCard = ({
|
||||||
setTimeoutId(null)
|
setTimeoutId(null)
|
||||||
setSecondsLeftToCancel(null)
|
setSecondsLeftToCancel(null)
|
||||||
})
|
})
|
||||||
}, 3000)
|
}, 2000)
|
||||||
|
|
||||||
setTimeoutId(id)
|
setTimeoutId(id)
|
||||||
}
|
}
|
||||||
|
@ -529,29 +529,45 @@ const ChoreCard = ({
|
||||||
)}
|
)}
|
||||||
{chore.labelsV2?.map((l, index) => {
|
{chore.labelsV2?.map((l, index) => {
|
||||||
return (
|
return (
|
||||||
<Chip
|
<div
|
||||||
variant='solid'
|
role='none'
|
||||||
key={`chorecard-${chore.id}-label-${l.id}`}
|
tabIndex={0}
|
||||||
color='primary'
|
onClick={e => {
|
||||||
sx={{
|
e.stopPropagation()
|
||||||
position: 'relative',
|
onChipClick({ label: l })
|
||||||
ml: index === 0 ? 0 : 0.5,
|
|
||||||
top: 2,
|
|
||||||
zIndex: 1,
|
|
||||||
backgroundColor: `${l?.color} !important`,
|
|
||||||
color: getTextColorFromBackgroundColor(l?.color),
|
|
||||||
|
|
||||||
// apply background color for th clickable button:
|
|
||||||
}}
|
}}
|
||||||
// onClick={e => {
|
onKeyDown={e => {
|
||||||
// e.stopPropagation()
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
// onChipClick({ label: l })
|
e.stopPropagation()
|
||||||
// }}
|
onChipClick({ label: l })
|
||||||
|
}
|
||||||
// startDecorator={getIconForLabel(label)}
|
}}
|
||||||
|
style={{ display: 'inline-block', cursor: 'pointer' }} // Make the wrapper clickable
|
||||||
|
key={`chorecard-${chore.id}-label-${l.id}`}
|
||||||
>
|
>
|
||||||
{l?.name}
|
<Chip
|
||||||
</Chip>
|
variant='solid'
|
||||||
|
color='primary'
|
||||||
|
sx={{
|
||||||
|
position: 'relative',
|
||||||
|
ml: index === 0 ? 0 : 0.5,
|
||||||
|
top: 2,
|
||||||
|
zIndex: 1,
|
||||||
|
backgroundColor: `${l?.color} !important`,
|
||||||
|
color: getTextColorFromBackgroundColor(l?.color),
|
||||||
|
|
||||||
|
// apply background color for th clickable button:
|
||||||
|
}}
|
||||||
|
// onClick={e => {
|
||||||
|
// e.stopPropagation()
|
||||||
|
// onChipClick({ label: l })
|
||||||
|
// }}
|
||||||
|
|
||||||
|
// startDecorator={getIconForLabel(label)}
|
||||||
|
>
|
||||||
|
{l?.name}
|
||||||
|
</Chip>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
@ -426,7 +426,6 @@ const MyChores = () => {
|
||||||
<Search />
|
<Search />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
<Divider orientation='vertical' />
|
|
||||||
|
|
||||||
<IconButtonWithMenu
|
<IconButtonWithMenu
|
||||||
title='Group by'
|
title='Group by'
|
||||||
|
@ -632,6 +631,7 @@ const MyChores = () => {
|
||||||
key={section.name + index}
|
key={section.name + index}
|
||||||
sx={{
|
sx={{
|
||||||
my: 0,
|
my: 0,
|
||||||
|
px: 0,
|
||||||
}}
|
}}
|
||||||
expanded={Boolean(openChoreSections[index])}
|
expanded={Boolean(openChoreSections[index])}
|
||||||
>
|
>
|
||||||
|
|
|
@ -31,7 +31,7 @@ const Sidepanel = ({ chores }) => {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Sheet
|
<Sheet
|
||||||
variant='outlined'
|
variant='plain'
|
||||||
sx={{
|
sx={{
|
||||||
p: 2,
|
p: 2,
|
||||||
// borderRadius: 'sm',
|
// borderRadius: 'sm',
|
||||||
|
|
|
@ -64,15 +64,15 @@ const ThingCard = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
variant='outlined'
|
variant='plain'
|
||||||
sx={{
|
sx={{
|
||||||
// display: 'flex',
|
display: 'flex',
|
||||||
// flexDirection: 'row', // Change to 'row'
|
flexDirection: 'column',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
p: 2,
|
p: 2,
|
||||||
boxShadow: 'sm',
|
boxShadow: 'sm',
|
||||||
borderRadius: 8,
|
borderRadius: 20,
|
||||||
mb: 1,
|
mb: 2,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { CSSTransition } from 'react-transition-group'
|
||||||
import { UserContext } from '../../contexts/UserContext'
|
import { UserContext } from '../../contexts/UserContext'
|
||||||
import useDebounce from '../../utils/Debounce'
|
import useDebounce from '../../utils/Debounce'
|
||||||
import { CreateChore } from '../../utils/Fetcher'
|
import { CreateChore } from '../../utils/Fetcher'
|
||||||
|
import { isPlusAccount } from '../../utils/Helpers'
|
||||||
import { useLabels } from '../Labels/LabelQueries'
|
import { useLabels } from '../Labels/LabelQueries'
|
||||||
import LearnMoreButton from './LearnMore'
|
import LearnMoreButton from './LearnMore'
|
||||||
const VALID_DAYS = {
|
const VALID_DAYS = {
|
||||||
|
@ -429,16 +430,22 @@ const TaskInput = ({ autoFocus, onChoreUpdate }) => {
|
||||||
assignedTo: userProfile.id,
|
assignedTo: userProfile.id,
|
||||||
assignStrategy: 'random',
|
assignStrategy: 'random',
|
||||||
isRolling: false,
|
isRolling: false,
|
||||||
|
notification: false,
|
||||||
description: description || null,
|
description: description || null,
|
||||||
labelsV2: [],
|
labelsV2: [],
|
||||||
priority: priority || 0,
|
priority: priority || 0,
|
||||||
status: 0,
|
status: 0,
|
||||||
|
frequencyType: 'once',
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frequency) {
|
if (frequency) {
|
||||||
chore.frequencyType = frequency.frequencyType
|
chore.frequencyType = frequency.frequencyType
|
||||||
chore.frequencyMetadata = frequency.frequencyMetadata
|
chore.frequencyMetadata = frequency.frequencyMetadata
|
||||||
chore.frequency = frequency.frequency
|
chore.frequency = frequency.frequency
|
||||||
|
if (isPlusAccount()) {
|
||||||
|
chore.notification = true
|
||||||
|
chore.notificationMetadata = { dueDate: true }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateChore(chore).then(resp => {
|
CreateChore(chore).then(resp => {
|
||||||
|
|
|
@ -124,7 +124,7 @@ const CalendarView = ({ chores }) => {
|
||||||
.map((chore, idx) => (
|
.map((chore, idx) => (
|
||||||
<Card
|
<Card
|
||||||
key={idx}
|
key={idx}
|
||||||
variant='soft'
|
variant='outlined'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
Navigate('/chores/' + chore.id)
|
Navigate('/chores/' + chore.id)
|
||||||
}}
|
}}
|
||||||
|
|
Loading…
Add table
Reference in a new issue