Refactor modals to use FadeModal component for consistent styling and improved user experience
- fix https://github.com/donetick/donetick/issues/222 - Replaced Modal and ModalDialog with FadeModal in LabelModal, PasswordChangeModal, SelectModal, TextModal, UserModal, WriteNFCModal, RedeemPointsModal, and AddTaskModal. - Updated modal structure and layout to maintain functionality while enhancing visual consistency. - Removed unused imports and commented-out code for cleaner codebase.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Box, Button, Modal, ModalDialog, Typography } from '@mui/joy'
|
||||
import React from 'react'
|
||||
import { Box, Button, Typography } from '@mui/joy'
|
||||
import FadeModal from '../../../components/common/FadeModal'
|
||||
|
||||
function ConfirmationModal({ config }) {
|
||||
const handleAction = isConfirmed => {
|
||||
@@ -7,38 +7,41 @@ function ConfirmationModal({ config }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={config?.isOpen} onClose={config?.onClose}>
|
||||
<ModalDialog>
|
||||
<Typography level='h4' mb={1}>
|
||||
{config?.title}
|
||||
</Typography>
|
||||
<FadeModal
|
||||
open={config?.isOpen}
|
||||
onClose={config?.onClose}
|
||||
size='sm'
|
||||
unmountDelay={250}
|
||||
>
|
||||
<Typography level='h4' mb={1}>
|
||||
{config?.title}
|
||||
</Typography>
|
||||
|
||||
<Typography level='body-md' gutterBottom>
|
||||
{config?.message}
|
||||
</Typography>
|
||||
<Typography level='body-md' gutterBottom>
|
||||
{config?.message}
|
||||
</Typography>
|
||||
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleAction(true)
|
||||
}}
|
||||
fullWidth
|
||||
sx={{ mr: 1 }}
|
||||
color={config.color ? config.color : 'primary'}
|
||||
>
|
||||
{config?.confirmText}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleAction(false)
|
||||
}}
|
||||
variant='outlined'
|
||||
>
|
||||
{config?.cancelText}
|
||||
</Button>
|
||||
</Box>
|
||||
</ModalDialog>
|
||||
</Modal>
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleAction(true)
|
||||
}}
|
||||
fullWidth
|
||||
sx={{ mr: 1 }}
|
||||
color={config.color ? config.color : 'primary'}
|
||||
>
|
||||
{config?.confirmText}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleAction(false)
|
||||
}}
|
||||
variant='outlined'
|
||||
>
|
||||
{config?.cancelText}
|
||||
</Button>
|
||||
</Box>
|
||||
</FadeModal>
|
||||
)
|
||||
}
|
||||
export default ConfirmationModal
|
||||
|
||||
@@ -4,14 +4,13 @@ import {
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
Input,
|
||||
Modal,
|
||||
ModalDialog,
|
||||
Option,
|
||||
Select,
|
||||
Textarea,
|
||||
Typography,
|
||||
} from '@mui/joy'
|
||||
import { useEffect, useState } from 'react'
|
||||
import FadeModal from '../../../components/common/FadeModal'
|
||||
|
||||
function CreateThingModal({ isOpen, onClose, onSave, currentThing }) {
|
||||
const [name, setName] = useState(currentThing?.name || '')
|
||||
@@ -59,87 +58,80 @@ function CreateThingModal({ isOpen, onClose, onSave, currentThing }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={isOpen} onClose={onClose}>
|
||||
<ModalDialog>
|
||||
{/* <ModalClose /> */}
|
||||
<Typography level='h4'>
|
||||
{currentThing?.id ? 'Edit' : 'Create'} Thing
|
||||
</Typography>
|
||||
<FadeModal open={isOpen} onClose={onClose}>
|
||||
<Typography level='h4'>
|
||||
{currentThing?.id ? 'Edit' : 'Create'} Thing
|
||||
</Typography>
|
||||
<FormControl>
|
||||
<Typography>Name</Typography>
|
||||
<Textarea
|
||||
placeholder='Thing name'
|
||||
value={name}
|
||||
onChange={e => setName(e.target.value)}
|
||||
sx={{ minWidth: 300 }}
|
||||
/>
|
||||
<FormHelperText color='danger'>{errors.name}</FormHelperText>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<Typography>Type</Typography>
|
||||
<Select value={type} sx={{ minWidth: 300 }}>
|
||||
{['text', 'number', 'boolean'].map(type => (
|
||||
<Option value={type} key={type} onClick={() => setType(type)}>
|
||||
{type.charAt(0).toUpperCase() + type.slice(1)}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
<FormHelperText color='danger'>{errors.type}</FormHelperText>
|
||||
</FormControl>
|
||||
{type === 'text' && (
|
||||
<FormControl>
|
||||
<Typography>Name</Typography>
|
||||
<Textarea
|
||||
placeholder='Thing name'
|
||||
value={name}
|
||||
onChange={e => setName(e.target.value)}
|
||||
<Typography>Value</Typography>
|
||||
<Input
|
||||
placeholder='Thing value'
|
||||
value={state || ''}
|
||||
onChange={e => setState(e.target.value)}
|
||||
sx={{ minWidth: 300 }}
|
||||
/>
|
||||
<FormHelperText color='danger'>{errors.name}</FormHelperText>
|
||||
<FormHelperText color='danger'>{errors.state}</FormHelperText>
|
||||
</FormControl>
|
||||
)}
|
||||
{type === 'number' && (
|
||||
<FormControl>
|
||||
<Typography>Type</Typography>
|
||||
<Select value={type} sx={{ minWidth: 300 }}>
|
||||
{['text', 'number', 'boolean'].map(type => (
|
||||
<Option value={type} key={type} onClick={() => setType(type)}>
|
||||
{type.charAt(0).toUpperCase() + type.slice(1)}
|
||||
<Typography>Value</Typography>
|
||||
<Input
|
||||
placeholder='Thing value'
|
||||
type='number'
|
||||
value={state || ''}
|
||||
onChange={e => {
|
||||
setState(e.target.value)
|
||||
}}
|
||||
sx={{ minWidth: 300 }}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
{type === 'boolean' && (
|
||||
<FormControl>
|
||||
<Typography>Value</Typography>
|
||||
<Select sx={{ minWidth: 300 }} value={state}>
|
||||
{['true', 'false'].map(value => (
|
||||
<Option value={value} key={value} onClick={() => setState(value)}>
|
||||
{value.charAt(0).toUpperCase() + value.slice(1)}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
<FormHelperText color='danger'>{errors.type}</FormHelperText>
|
||||
</FormControl>
|
||||
{type === 'text' && (
|
||||
<FormControl>
|
||||
<Typography>Value</Typography>
|
||||
<Input
|
||||
placeholder='Thing value'
|
||||
value={state || ''}
|
||||
onChange={e => setState(e.target.value)}
|
||||
sx={{ minWidth: 300 }}
|
||||
/>
|
||||
<FormHelperText color='danger'>{errors.state}</FormHelperText>
|
||||
</FormControl>
|
||||
)}
|
||||
{type === 'number' && (
|
||||
<FormControl>
|
||||
<Typography>Value</Typography>
|
||||
<Input
|
||||
placeholder='Thing value'
|
||||
type='number'
|
||||
value={state || ''}
|
||||
onChange={e => {
|
||||
setState(e.target.value)
|
||||
}}
|
||||
sx={{ minWidth: 300 }}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
{type === 'boolean' && (
|
||||
<FormControl>
|
||||
<Typography>Value</Typography>
|
||||
<Select sx={{ minWidth: 300 }} value={state}>
|
||||
{['true', 'false'].map(value => (
|
||||
<Option
|
||||
value={value}
|
||||
key={value}
|
||||
onClick={() => setState(value)}
|
||||
>
|
||||
{value.charAt(0).toUpperCase() + value.slice(1)}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
)}
|
||||
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button onClick={handleSave} fullWidth sx={{ mr: 1 }}>
|
||||
{currentThing?.id ? 'Update' : 'Create'}
|
||||
</Button>
|
||||
<Button onClick={onClose} variant='outlined'>
|
||||
{currentThing?.id ? 'Cancel' : 'Close'}
|
||||
</Button>
|
||||
</Box>
|
||||
</ModalDialog>
|
||||
</Modal>
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button onClick={handleSave} fullWidth sx={{ mr: 1 }}>
|
||||
{currentThing?.id ? 'Update' : 'Create'}
|
||||
</Button>
|
||||
<Button onClick={onClose} variant='outlined'>
|
||||
{currentThing?.id ? 'Cancel' : 'Close'}
|
||||
</Button>
|
||||
</Box>
|
||||
</FadeModal>
|
||||
)
|
||||
}
|
||||
export default CreateThingModal
|
||||
|
||||
@@ -3,13 +3,12 @@ import {
|
||||
Button,
|
||||
FormControl,
|
||||
Input,
|
||||
Modal,
|
||||
ModalDialog,
|
||||
Option,
|
||||
Select,
|
||||
Typography,
|
||||
} from '@mui/joy'
|
||||
import { useEffect, useState } from 'react'
|
||||
import FadeModal from '../../../components/common/FadeModal'
|
||||
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useNotification } from '../../../service/NotificationProvider.jsx'
|
||||
@@ -58,29 +57,9 @@ function LabelModal({ isOpen, onClose, label }) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Mutation for saving labels
|
||||
// const saveLabelMutation = useMutation(
|
||||
// newLabel =>
|
||||
// label
|
||||
// ? UpdateLabel({ id: label.id, ...newLabel })
|
||||
// : CreateLabel(newLabel),
|
||||
// {
|
||||
// onSuccess: () => {
|
||||
// queryClient.invalidateQueries('labels')
|
||||
// onClose()
|
||||
// },
|
||||
// onError: () => {
|
||||
// setError('Failed to save label. Please try again.')
|
||||
// },
|
||||
// },
|
||||
// )
|
||||
|
||||
const handleSave = () => {
|
||||
if (!validateLabel()) return
|
||||
const saveLabel = label?.id && label.id !== -1 ? UpdateLabel : CreateLabel
|
||||
// ? { id: label.id, name: labelName, color }
|
||||
// : { name: labelName, color }
|
||||
// saveLabelMutation.mutate({ name: labelName, color })
|
||||
saveLabel({
|
||||
id: label?.id,
|
||||
name: labelName,
|
||||
@@ -110,79 +89,77 @@ function LabelModal({ isOpen, onClose, label }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={isOpen} onClose={onClose}>
|
||||
<ModalDialog>
|
||||
<Typography level='title-md' mb={1}>
|
||||
{label ? 'Edit Label' : 'Add Label'}
|
||||
<FadeModal open={isOpen} onClose={onClose}>
|
||||
<Typography level='title-md' mb={1}>
|
||||
{label ? 'Edit Label' : 'Add Label'}
|
||||
</Typography>
|
||||
|
||||
<FormControl>
|
||||
<Typography gutterBottom level='body-sm' alignSelf='start'>
|
||||
Name
|
||||
</Typography>
|
||||
<Input
|
||||
fullWidth
|
||||
id='labelName'
|
||||
value={labelName}
|
||||
onChange={e => setLabelName(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<Typography gutterBottom level='body-sm' alignSelf='start'>
|
||||
Name
|
||||
</Typography>
|
||||
<Input
|
||||
fullWidth
|
||||
id='labelName'
|
||||
value={labelName}
|
||||
onChange={e => setLabelName(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<Typography gutterBottom level='body-sm' alignSelf='start'>
|
||||
Color
|
||||
</Typography>
|
||||
<Select
|
||||
value={color}
|
||||
onChange={(e, value) => value && setColor(value)}
|
||||
renderValue={selected => (
|
||||
<Typography
|
||||
startDecorator={
|
||||
<Box
|
||||
className='size-4'
|
||||
borderRadius={10}
|
||||
sx={{ background: selected.value }}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{selected.label}
|
||||
</Typography>
|
||||
)}
|
||||
>
|
||||
{LABEL_COLORS.map(val => (
|
||||
<Option key={val.value} value={val.value}>
|
||||
<Box className='flex items-center justify-between'>
|
||||
<Box
|
||||
width={20}
|
||||
height={20}
|
||||
borderRadius={10}
|
||||
sx={{ background: val.value }}
|
||||
/>
|
||||
<Typography sx={{ ml: 1 }} variant='caption'>
|
||||
{val.name}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<Typography gutterBottom level='body-sm' alignSelf='start'>
|
||||
Color
|
||||
</Typography>
|
||||
<Select
|
||||
value={color}
|
||||
onChange={(e, value) => value && setColor(value)}
|
||||
renderValue={selected => (
|
||||
<Typography
|
||||
startDecorator={
|
||||
<Box
|
||||
className='size-4'
|
||||
borderRadius={10}
|
||||
sx={{ background: selected.value }}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{selected.label}
|
||||
</Typography>
|
||||
)}
|
||||
>
|
||||
{LABEL_COLORS.map(val => (
|
||||
<Option key={val.value} value={val.value}>
|
||||
<Box className='flex items-center justify-between'>
|
||||
<Box
|
||||
width={20}
|
||||
height={20}
|
||||
borderRadius={10}
|
||||
sx={{ background: val.value }}
|
||||
/>
|
||||
<Typography sx={{ ml: 1 }} variant='caption'>
|
||||
{val.name}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
{error && (
|
||||
<Typography color='warning' level='body-sm'>
|
||||
{error}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<Typography color='warning' level='body-sm'>
|
||||
{error}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
<Box display='flex' justifyContent='space-around' mt={1}>
|
||||
<Button onClick={handleSave} fullWidth sx={{ mr: 1 }}>
|
||||
{label ? 'Save Changes' : 'Add Label'}
|
||||
</Button>
|
||||
<Button onClick={onClose} variant='outlined'>
|
||||
Cancel
|
||||
</Button>
|
||||
</Box>
|
||||
</ModalDialog>
|
||||
</Modal>
|
||||
<Box display='flex' justifyContent='space-around' mt={1}>
|
||||
<Button onClick={handleSave} fullWidth sx={{ mr: 1 }}>
|
||||
{label ? 'Save Changes' : 'Add Label'}
|
||||
</Button>
|
||||
<Button onClick={onClose} variant='outlined'>
|
||||
Cancel
|
||||
</Button>
|
||||
</Box>
|
||||
</FadeModal>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,10 @@ import {
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
Input,
|
||||
Modal,
|
||||
ModalDialog,
|
||||
Typography,
|
||||
} from '@mui/joy'
|
||||
import React, { useEffect } from 'react'
|
||||
import FadeModal from '../../../components/common/FadeModal'
|
||||
|
||||
function PassowrdChangeModal({ isOpen, onClose }) {
|
||||
const [password, setPassword] = React.useState('')
|
||||
@@ -40,78 +39,76 @@ function PassowrdChangeModal({ isOpen, onClose }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={isOpen} onClose={onClose}>
|
||||
<ModalDialog>
|
||||
<Typography level='h4' mb={1}>
|
||||
<FadeModal open={isOpen} onClose={onClose}>
|
||||
<Typography level='h4' mb={1}>
|
||||
Change Password
|
||||
</Typography>
|
||||
|
||||
<Typography level='body-md' gutterBottom>
|
||||
Please enter your new password.
|
||||
</Typography>
|
||||
<FormControl>
|
||||
<Typography level='body2' alignSelf={'start'}>
|
||||
New Password
|
||||
</Typography>
|
||||
<Input
|
||||
margin='normal'
|
||||
required
|
||||
fullWidth
|
||||
name='password'
|
||||
label='Password'
|
||||
type='password'
|
||||
id='password'
|
||||
value={password}
|
||||
onChange={e => {
|
||||
setPasswordTouched(true)
|
||||
setPassword(e.target.value)
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<Typography level='body2' alignSelf={'start'}>
|
||||
Confirm Password
|
||||
</Typography>
|
||||
<Input
|
||||
margin='normal'
|
||||
required
|
||||
fullWidth
|
||||
name='confirmPassword'
|
||||
label='confirmPassword'
|
||||
type='password'
|
||||
id='confirmPassword'
|
||||
value={confirmPassword}
|
||||
onChange={e => {
|
||||
setConfirmPasswordTouched(true)
|
||||
setConfirmPassword(e.target.value)
|
||||
}}
|
||||
/>
|
||||
|
||||
<FormHelperText>{passwordError}</FormHelperText>
|
||||
</FormControl>
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button
|
||||
disabled={passwordError != null}
|
||||
onClick={() => {
|
||||
handleAction(true)
|
||||
}}
|
||||
fullWidth
|
||||
sx={{ mr: 1 }}
|
||||
>
|
||||
Change Password
|
||||
</Typography>
|
||||
|
||||
<Typography level='body-md' gutterBottom>
|
||||
Please enter your new password.
|
||||
</Typography>
|
||||
<FormControl>
|
||||
<Typography level='body2' alignSelf={'start'}>
|
||||
New Password
|
||||
</Typography>
|
||||
<Input
|
||||
margin='normal'
|
||||
required
|
||||
fullWidth
|
||||
name='password'
|
||||
label='Password'
|
||||
type='password'
|
||||
id='password'
|
||||
value={password}
|
||||
onChange={e => {
|
||||
setPasswordTouched(true)
|
||||
setPassword(e.target.value)
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<Typography level='body2' alignSelf={'start'}>
|
||||
Confirm Password
|
||||
</Typography>
|
||||
<Input
|
||||
margin='normal'
|
||||
required
|
||||
fullWidth
|
||||
name='confirmPassword'
|
||||
label='confirmPassword'
|
||||
type='password'
|
||||
id='confirmPassword'
|
||||
value={confirmPassword}
|
||||
onChange={e => {
|
||||
setConfirmPasswordTouched(true)
|
||||
setConfirmPassword(e.target.value)
|
||||
}}
|
||||
/>
|
||||
|
||||
<FormHelperText>{passwordError}</FormHelperText>
|
||||
</FormControl>
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button
|
||||
disabled={passwordError != null}
|
||||
onClick={() => {
|
||||
handleAction(true)
|
||||
}}
|
||||
fullWidth
|
||||
sx={{ mr: 1 }}
|
||||
>
|
||||
Change Password
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleAction(false)
|
||||
}}
|
||||
variant='outlined'
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</Box>
|
||||
</ModalDialog>
|
||||
</Modal>
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleAction(false)
|
||||
}}
|
||||
variant='outlined'
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</Box>
|
||||
</FadeModal>
|
||||
)
|
||||
}
|
||||
export default PassowrdChangeModal
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Modal,
|
||||
ModalDialog,
|
||||
Option,
|
||||
Select,
|
||||
Typography,
|
||||
} from '@mui/joy'
|
||||
import { Box, Button, Option, Select, Typography } from '@mui/joy'
|
||||
import React from 'react'
|
||||
import FadeModal from '../../../components/common/FadeModal'
|
||||
|
||||
function SelectModal({ isOpen, onClose, onSave, options, title, displayKey,placeholder }) {
|
||||
function SelectModal({
|
||||
isOpen,
|
||||
onClose,
|
||||
onSave,
|
||||
options,
|
||||
title,
|
||||
displayKey,
|
||||
placeholder,
|
||||
}) {
|
||||
const [selected, setSelected] = React.useState(null)
|
||||
const handleSave = () => {
|
||||
onSave(options.find(item => item.id === selected))
|
||||
@@ -17,33 +18,31 @@ function SelectModal({ isOpen, onClose, onSave, options, title, displayKey,place
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={isOpen} onClose={onClose}>
|
||||
<ModalDialog>
|
||||
<Typography variant='h4'>{title}</Typography>
|
||||
<Select placeholder={placeholder}>
|
||||
{options.map((item, index) => (
|
||||
<Option
|
||||
value={item.id}
|
||||
key={item[displayKey]}
|
||||
onClick={() => {
|
||||
setSelected(item.id)
|
||||
}}
|
||||
>
|
||||
{item[displayKey]}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
<FadeModal open={isOpen} onClose={onClose}>
|
||||
<Typography variant='h4'>{title}</Typography>
|
||||
<Select placeholder={placeholder}>
|
||||
{options.map((item, index) => (
|
||||
<Option
|
||||
value={item.id}
|
||||
key={item[displayKey]}
|
||||
onClick={() => {
|
||||
setSelected(item.id)
|
||||
}}
|
||||
>
|
||||
{item[displayKey]}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button onClick={handleSave} fullWidth sx={{ mr: 1 }}>
|
||||
Save
|
||||
</Button>
|
||||
<Button onClick={onClose} variant='outlined'>
|
||||
Cancel
|
||||
</Button>
|
||||
</Box>
|
||||
</ModalDialog>
|
||||
</Modal>
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button onClick={handleSave} fullWidth sx={{ mr: 1 }}>
|
||||
Save
|
||||
</Button>
|
||||
<Button onClick={onClose} variant='outlined'>
|
||||
Cancel
|
||||
</Button>
|
||||
</Box>
|
||||
</FadeModal>
|
||||
)
|
||||
}
|
||||
export default SelectModal
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Box, Button, Modal, ModalDialog, Textarea, Typography } from '@mui/joy'
|
||||
import { Box, Button, Textarea, Typography } from '@mui/joy'
|
||||
import { useState } from 'react'
|
||||
import FadeModal from '../../../components/common/FadeModal'
|
||||
|
||||
function TextModal({
|
||||
isOpen,
|
||||
@@ -18,29 +19,26 @@ function TextModal({
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={isOpen} onClose={onClose}>
|
||||
<ModalDialog>
|
||||
{/* <ModalClose /> */}
|
||||
<Typography variant='h4'>{title}</Typography>
|
||||
<Textarea
|
||||
placeholder='Type in here…'
|
||||
value={text}
|
||||
onChange={e => setText(e.target.value)}
|
||||
minRows={2}
|
||||
maxRows={4}
|
||||
sx={{ minWidth: 300 }}
|
||||
/>
|
||||
<FadeModal open={isOpen} onClose={onClose}>
|
||||
<Typography variant='h4'>{title}</Typography>
|
||||
<Textarea
|
||||
placeholder='Type in here…'
|
||||
value={text}
|
||||
onChange={e => setText(e.target.value)}
|
||||
minRows={2}
|
||||
maxRows={4}
|
||||
sx={{ minWidth: 300 }}
|
||||
/>
|
||||
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button onClick={handleSave} fullWidth sx={{ mr: 1 }}>
|
||||
{okText ? okText : 'Save'}
|
||||
</Button>
|
||||
<Button onClick={onClose} variant='outlined'>
|
||||
{cancelText ? cancelText : 'Cancel'}
|
||||
</Button>
|
||||
</Box>
|
||||
</ModalDialog>
|
||||
</Modal>
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button onClick={handleSave} fullWidth sx={{ mr: 1 }}>
|
||||
{okText ? okText : 'Save'}
|
||||
</Button>
|
||||
<Button onClick={onClose} variant='outlined'>
|
||||
{cancelText ? cancelText : 'Cancel'}
|
||||
</Button>
|
||||
</Box>
|
||||
</FadeModal>
|
||||
)
|
||||
}
|
||||
export default TextModal
|
||||
|
||||
@@ -1,57 +1,44 @@
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
List,
|
||||
ListItem,
|
||||
Modal,
|
||||
ModalDialog,
|
||||
ModalOverflow,
|
||||
Typography,
|
||||
} from '@mui/joy'
|
||||
import { Avatar, Box, Button, List, ListItem, Typography } from '@mui/joy'
|
||||
import FadeModal from '../../../components/common/FadeModal'
|
||||
|
||||
const UserModal = ({ isOpen, performers = [], onSelect, onClose }) => {
|
||||
return (
|
||||
<Modal open={isOpen} onClose={onClose}>
|
||||
<ModalOverflow>
|
||||
<ModalDialog size='md' sx={{ minWidth: 360 }}>
|
||||
<Typography level='h4' sx={{ mb: 2 }}>
|
||||
Select User
|
||||
</Typography>
|
||||
<List sx={{ mb: 2 }}>
|
||||
{performers.map(user => (
|
||||
<ListItem
|
||||
key={user.id}
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
'&:hover': {
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.04)',
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
onSelect(user)
|
||||
onClose()
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||
<Avatar
|
||||
size='lg'
|
||||
src={user.image || user.avatar}
|
||||
alt={user.displayName || user.name}
|
||||
/>
|
||||
<Typography>{user.displayName || user.name}</Typography>
|
||||
</Box>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end', gap: 1 }}>
|
||||
<Button variant='outlined' color='neutral' onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Box>
|
||||
</ModalDialog>
|
||||
</ModalOverflow>
|
||||
</Modal>
|
||||
<FadeModal open={isOpen} onClose={onClose} size='md' fullWidth>
|
||||
<Typography level='h4' sx={{ mb: 2 }}>
|
||||
Select User
|
||||
</Typography>
|
||||
<List sx={{ mb: 2 }}>
|
||||
{performers.map(user => (
|
||||
<ListItem
|
||||
key={user.id}
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
'&:hover': {
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.04)',
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
onSelect(user)
|
||||
onClose()
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||
<Avatar
|
||||
size='lg'
|
||||
src={user.image || user.avatar}
|
||||
alt={user.displayName || user.name}
|
||||
/>
|
||||
<Typography>{user.displayName || user.name}</Typography>
|
||||
</Box>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end', gap: 1 }}>
|
||||
<Button variant='outlined' color='neutral' onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Box>
|
||||
</FadeModal>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
import { CopyAll } from '@mui/icons-material'
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Input,
|
||||
ListItem,
|
||||
Modal,
|
||||
ModalDialog,
|
||||
Typography,
|
||||
} from '@mui/joy'
|
||||
import React, { useState } from 'react'
|
||||
import { Box, Button, Checkbox, Input, ListItem, Typography } from '@mui/joy'
|
||||
import { useState } from 'react'
|
||||
import FadeModal from '../../../components/common/FadeModal'
|
||||
|
||||
function WriteNFCModal({ config }) {
|
||||
const [nfcStatus, setNfcStatus] = useState('idle') // 'idle', 'writing', 'success', 'error'
|
||||
@@ -60,63 +52,61 @@ function WriteNFCModal({ config }) {
|
||||
return url
|
||||
}
|
||||
return (
|
||||
<Modal open={config?.isOpen} onClose={handleClose}>
|
||||
<ModalDialog>
|
||||
<Typography level='h4' mb={1}>
|
||||
{nfcStatus === 'success' ? 'Success!' : 'Write to NFC'}
|
||||
</Typography>
|
||||
<FadeModal open={config?.isOpen} onClose={handleClose}>
|
||||
<Typography level='h4' mb={1}>
|
||||
{nfcStatus === 'success' ? 'Success!' : 'Write to NFC'}
|
||||
</Typography>
|
||||
|
||||
{nfcStatus === 'success' ? (
|
||||
{nfcStatus === 'success' ? (
|
||||
<Typography level='body-md' gutterBottom>
|
||||
URL written to NFC tag successfully!
|
||||
</Typography>
|
||||
) : (
|
||||
<>
|
||||
<Typography level='body-md' gutterBottom>
|
||||
URL written to NFC tag successfully!
|
||||
{nfcStatus === 'error'
|
||||
? errorMessage
|
||||
: 'Press the button below to write to NFC.'}
|
||||
</Typography>
|
||||
) : (
|
||||
<>
|
||||
<Typography level='body-md' gutterBottom>
|
||||
{nfcStatus === 'error'
|
||||
? errorMessage
|
||||
: 'Press the button below to write to NFC.'}
|
||||
</Typography>
|
||||
<Input
|
||||
value={getURL()}
|
||||
fullWidth
|
||||
readOnly
|
||||
label='URL'
|
||||
sx={{ mt: 1 }}
|
||||
endDecorator={
|
||||
<CopyAll
|
||||
sx={{ cursor: 'pointer' }}
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(getURL())
|
||||
alert('URL copied to clipboard!')
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<ListItem>
|
||||
<Checkbox
|
||||
checked={isAutoCompleteWhenScan}
|
||||
onChange={e => setIsAutoCompleteWhenScan(e.target.checked)}
|
||||
label='Auto-complete when scanned'
|
||||
<Input
|
||||
value={getURL()}
|
||||
fullWidth
|
||||
readOnly
|
||||
label='URL'
|
||||
sx={{ mt: 1 }}
|
||||
endDecorator={
|
||||
<CopyAll
|
||||
sx={{ cursor: 'pointer' }}
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(getURL())
|
||||
alert('URL copied to clipboard!')
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button
|
||||
onClick={() => writeToNFC(getURL())}
|
||||
fullWidth
|
||||
sx={{ mr: 1 }}
|
||||
disabled={nfcStatus === 'writing'}
|
||||
>
|
||||
Write NFC
|
||||
</Button>
|
||||
<Button onClick={requestNFCAccess} variant='outlined'>
|
||||
Request Access
|
||||
</Button>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</ModalDialog>
|
||||
</Modal>
|
||||
}
|
||||
/>
|
||||
<ListItem>
|
||||
<Checkbox
|
||||
checked={isAutoCompleteWhenScan}
|
||||
onChange={e => setIsAutoCompleteWhenScan(e.target.checked)}
|
||||
label='Auto-complete when scanned'
|
||||
/>
|
||||
</ListItem>
|
||||
<Box display={'flex'} justifyContent={'space-around'} mt={1}>
|
||||
<Button
|
||||
onClick={() => writeToNFC(getURL())}
|
||||
fullWidth
|
||||
sx={{ mr: 1 }}
|
||||
disabled={nfcStatus === 'writing'}
|
||||
>
|
||||
Write NFC
|
||||
</Button>
|
||||
<Button onClick={requestNFCAccess} variant='outlined'>
|
||||
Request Access
|
||||
</Button>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</FadeModal>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user