Make label Clickable

Fix changing URL for selfhosted
Update styling for calendar and thingview
This commit is contained in:
Mo Tarbin 2025-02-01 01:51:20 -05:00
parent 4527b229ed
commit ba149d0e96
10 changed files with 171 additions and 166 deletions

View file

@ -25,6 +25,7 @@ class ApiManager {
} }
updateApiURL(url) { updateApiURL(url) {
this.customServerURL = url this.customServerURL = url
this.init()
} }
} }

View file

@ -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

View file

@ -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'>

View file

@ -435,6 +435,7 @@ const ChoreView = () => {
sx={{ sx={{
p: 2, p: 2,
borderRadius: 'lg', borderRadius: 'lg',
mb: 1,
}} }}
> >
<IconButton <IconButton

View file

@ -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>

View file

@ -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])}
> >

View file

@ -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',

View file

@ -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>

View file

@ -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 => {

View file

@ -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)
}} }}