Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/CD_preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,12 @@ jobs:
- name: Comment PR with preview URL
if: github.event_name == 'pull_request'
env:
PREVIEW_URL: ${{ steps.preview-url.outputs.url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr comment ${{ github.event.pull_request.number }} --body "$(cat <<'EOF'
gh pr comment ${{ github.event.pull_request.number }} --body "$(cat <<EOF
## Preview Deployment

**Preview URL:** $PREVIEW_URL
**Preview URL:** ${{ steps.preview-url.outputs.url }}

**Note:** This preview uses the staging API endpoints and has auth disabled for testing.
EOF
Expand Down
74 changes: 40 additions & 34 deletions src/components/Controlled/ControlledSelectField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,38 +32,44 @@ export const ControlledSelectField = <T,>({
<Controller
name={name as Path<T>}
control={control as unknown as Control<T>}
render={({ field, fieldState }) => (
<FormControl fullWidth error={!!fieldState.error} required={required}>
<InputLabel id={labelId ? labelId : undefined}>
{label}
{showAsterisk ? (
<>
{' '}
<Box component="span" sx={{ color: 'error.main' }}>
*
</Box>
</>
) : null}
</InputLabel>
<Select
variant="outlined"
label={label}
labelId={labelId ? labelId : undefined}
{...omit(field, ['required'])}
{...omit(selectProps, ['required'])}
value={field.value ?? ''}
onOpen={onOpen}
>
{options.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</Select>
{fieldState?.error && (
<FormHelperText>{fieldState?.error?.message}</FormHelperText>
)}
</FormControl>
)}
render={({ field, fieldState }) => {
const resolvedId = selectProps.id ?? String(name)
const resolvedLabelId = labelId ?? `${resolvedId}-label`

return (
<FormControl fullWidth error={!!fieldState.error} required={required}>
<InputLabel id={resolvedLabelId}>
{label}
{showAsterisk ? (
<>
{' '}
<Box component="span" sx={{ color: 'error.main' }}>
*
</Box>
</>
) : null}
</InputLabel>
<Select
variant="outlined"
label={label}
id={resolvedId}
labelId={resolvedLabelId}
{...omit(field, ['required'])}
{...omit(selectProps, ['required'])}
value={field.value ?? ''}
onOpen={onOpen}
>
{options.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</Select>
{fieldState?.error && (
<FormHelperText>{fieldState?.error?.message}</FormHelperText>
)}
</FormControl>
)
}}
/>
)
)
118 changes: 55 additions & 63 deletions src/components/Controlled/ControlledSelectWithChipsField.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import React, { useEffect } from 'react'
import {
Select,
MenuItem,
Expand All @@ -10,7 +10,7 @@ import {
Box,
SelectChangeEvent,
} from '@mui/material'
import { Controller, Control, Path } from 'react-hook-form'
import { Control, Path, useController } from 'react-hook-form'

export const ControlledSelectWithChipsField = <T,>({
control,
Expand All @@ -19,7 +19,7 @@ export const ControlledSelectWithChipsField = <T,>({
options,
required,
multiple,
chipLimit = 3,
chipLimit = Number.POSITIVE_INFINITY,
clearChipsSignal,
resetClearChipsSignal,
...selectProps
Expand All @@ -31,78 +31,70 @@ export const ControlledSelectWithChipsField = <T,>({
required?: boolean
multiple?: boolean
chipLimit?: number
clearChipsSignal: boolean
resetClearChipsSignal: () => void
clearChipsSignal?: boolean
resetClearChipsSignal?: () => void
} & SelectProps) => {
const [selectedChips, setSelectedChips] = useState<string[]>([])
const {
field,
fieldState,
} = useController({
name: name as Path<T>,
control: control as unknown as Control<T>,
})

useEffect(() => {
if (clearChipsSignal) {
setSelectedChips([])
resetClearChipsSignal()
field.onChange([])
resetClearChipsSignal?.()
}
}, [clearChipsSignal, resetClearChipsSignal])
}, [clearChipsSignal, field, resetClearChipsSignal])

const handleSelectChange = (event: SelectChangeEvent<string[]>) => {
const selectedValues = event.target.value as string[]

if (selectedValues.length <= chipLimit) {
setSelectedChips(selectedValues)
} else {
// Enforce chip limit by replacing the oldest chip with the new selection
const updatedChips = [...selectedValues]
updatedChips.shift() // Remove the oldest chip
setSelectedChips(updatedChips)
}
const nextValue =
selectedValues.length <= chipLimit
? selectedValues
: selectedValues.slice(-chipLimit)
field.onChange(nextValue)
}

const selectedValues = Array.isArray(field.value) ? field.value : []
const resolvedId = selectProps.id ?? String(name)
const resolvedLabelId = `${resolvedId}-label`

return (
<Controller
name={name as Path<T>}
control={control as unknown as Control<T>}
render={({ field, fieldState }) => (
<FormControl fullWidth error={!!fieldState.error} required={required}>
<InputLabel>{label}</InputLabel>
<Select
label={label}
multiple={multiple}
{...field}
{...selectProps}
value={selectedChips}
onChange={(event: SelectChangeEvent<string[]>) => {
const { value: selectedValues } = event.target
              if (selectedValues.length <= chipLimit) {
                field.onChange(selectedValues)
              } else {
                field.onChange(selectedValues.slice(-chipLimit))
              }
handleSelectChange(event)
}}
renderValue={(selected: string[]) => (
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
{selected?.map((value: string) => (
<Chip
key={value}
label={
options.find((option) => option.value === value)?.label
}
color="primary"
/>
))}
</Box>
)}
>
{options.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
<FormControl fullWidth error={!!fieldState.error} required={required}>
<InputLabel id={resolvedLabelId}>{label}</InputLabel>
<Select
label={label}
id={resolvedId}
labelId={resolvedLabelId}
multiple={multiple}
{...field}
{...selectProps}
value={selectedValues}
onChange={handleSelectChange}
renderValue={(selected: string[]) => (
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
{selected?.map((value: string) => (
<Chip
key={value}
label={options.find((option) => option.value === value)?.label}
color="primary"
/>
))}
</Select>
{fieldState?.error && (
<FormHelperText>{fieldState?.error?.message}</FormHelperText>
)}
</FormControl>
</Box>
)}
>
{options.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</Select>
{fieldState?.error && (
<FormHelperText>{fieldState?.error?.message}</FormHelperText>
)}
/>
</FormControl>
)
}
9 changes: 9 additions & 0 deletions src/components/Controlled/ControlledTextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ export const ControlledTextField = <T,>({
showAsterisk?: boolean
warning?: boolean
} & TextFieldProps) => {
const inputLabelProps =
type === 'date'
? {
...(textFieldProps.InputLabelProps ?? {}),
shrink: textFieldProps.InputLabelProps?.shrink ?? true,
}
: textFieldProps.InputLabelProps

return (
<Controller
name={name as Path<T>}
Expand All @@ -46,6 +54,7 @@ export const ControlledTextField = <T,>({
error={!!fieldState?.error}
helperText={fieldState?.error?.message || ''}
type={type}
InputLabelProps={inputLabelProps}
fullWidth
multiline={multiline}
minRows={multiline ? minRows : undefined}
Expand Down
Loading
Loading