Skip to content

Commit

Permalink
feat: added drag and drop for ordering material in eventitem
Browse files Browse the repository at this point in the history
  • Loading branch information
alasdairwilson committed May 29, 2024
1 parent b32f699 commit 70b47ca
Show file tree
Hide file tree
Showing 6 changed files with 288 additions and 90 deletions.
46 changes: 46 additions & 0 deletions components/forms/EventItemAdder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React, { useState } from "react"
import Stack from "components/ui/Stack"
import type { FieldValues } from "react-hook-form"
import { Button } from "@mui/material"
import SelectSectionField from "components/forms/SelectSectionField"
import type { Option } from "components/forms/SelectSectionField"

interface EventItemAdderProps<T extends FieldValues> {
sectionsOptions: Option[]
selectedOptions: Option[]
setSelectedOptions: React.Dispatch<React.SetStateAction<Option[]>>
handleAddClick: () => void
inputValue?: string
setInputValue: React.Dispatch<React.SetStateAction<string>>
className?: string
}

function EventItemAdder({
sectionsOptions,
selectedOptions,
setSelectedOptions,
handleAddClick,
inputValue,
setInputValue,
className,
}: EventItemAdderProps<FieldValues>) {
return (
<Stack direction="row">
<SelectSectionField
label="Section"
name=""
options={sectionsOptions}
selectedOptions={selectedOptions}
setSelectedOptions={setSelectedOptions}
inputValue={inputValue}
setInputValue={setInputValue}
className={className}
/>
<Button onClick={handleAddClick} variant="contained" size="small" className="rounded">
Add Sections
</Button>
</Stack>
)
}

export default EventItemAdder
99 changes: 53 additions & 46 deletions components/forms/SelectSectionField.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import React, { useState } from "react"
import React from "react"
import { useForm, Control, Controller, FieldPath, FieldValues } from "react-hook-form"
import { Autocomplete, TextField, Checkbox } from "@mui/material"
import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank"
import CheckBoxIcon from "@mui/icons-material/CheckBox"
import { Button } from "flowbite-react"
import { set } from "cypress/types/lodash"
import { Chip } from "@mui/material"

const icon = <CheckBoxOutlineBlankIcon fontSize="small" />
const checkedIcon = <CheckBoxIcon fontSize="small" />

type Option = {
export type Option = {
value: any
label: string
}
Expand All @@ -18,64 +17,72 @@ type Props<T extends FieldValues> = {
label?: string
name: FieldPath<T>
options: Option[]
control: Control<T>
rules?: Object
className?: React.ComponentProps<"div">["className"]
selectedOptions: Option[]
setSelectedOptions: React.Dispatch<React.SetStateAction<Option[]>>
inputValue?: string
setInputValue: React.Dispatch<React.SetStateAction<string>>
}

function SelectSectionField<T extends FieldValues>({
label,
name,
options,
control,
rules,
className,
selectedOptions,
setSelectedOptions,
inputValue,
setInputValue,
}: Props<T>): React.ReactElement {
const labelId = `${name}-label`
const [inputValue, setInputValue] = useState("")

const filterOptions = (options: Option[], { inputValue }: { inputValue: string }) => {
return options.filter((option) => option.label.toLowerCase().includes(inputValue.toLowerCase()))
}
return (
<Controller
name={name}
control={control}
rules={rules}
render={({ field: { onChange, value }, fieldState: { error } }) => (
<div className={className} id="select">
<Autocomplete
multiple
inputValue={inputValue}
disableCloseOnSelect={true}
onChange={(event, newValue) => setSelectedOptions(newValue)}
id={name}
options={options}
getOptionLabel={(option) => option.label}
filterOptions={(options) => options}
isOptionEqualToValue={(option, value) => option.value === value.value}
sx={{ width: 1000 }}
renderOption={(props, option, { selected }) => (
<li {...props}>
<Checkbox icon={icon} checkedIcon={checkedIcon} style={{ marginRight: 8 }} checked={selected} />
{option.label}
</li>
)}
renderInput={(params) => (
<TextField
{...params}
label={labelId}
error={!!error}
onChange={(e) => setInputValue(e.target.value)}
variant="outlined"
/>
)}
<div className={className} id="select">
<Autocomplete
multiple
inputValue={inputValue}
disableCloseOnSelect={true}
onChange={(event, newValue) => setSelectedOptions(newValue)}
value={selectedOptions}
id={name}
options={options}
getOptionLabel={(option) => option.label}
filterOptions={filterOptions}
isOptionEqualToValue={(option, value) => option.value === value.value}
sx={{ width: 1000 }}
renderOption={(props, option, { selected }) => (
<li {...props}>
<Checkbox icon={icon} checkedIcon={checkedIcon} style={{ marginRight: 8 }} checked={selected} />
{option.label}
</li>
)}
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<Chip
label={option.label}
{...getTagProps({ index })}
className="dark:bg-teal-500 dark:text-white"
key={`chip-${option.value}`}
/>
))
}
renderInput={(params) => (
<TextField
{...params}
placeholder="Choose Sections"
label={name}
error={false}
onChange={(e) => setInputValue(e.target.value)}
variant="outlined"
className="block w-full rounded-lg border disabled:cursor-not-allowed disabled:opacity-50 bg-gray-50
border-gray-300 text-gray-900 focus:border-cyan-500 focus:ring-cyan-500 dark:border-gray-600
dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-cyan-500 dark:focus:ring-cyan-500"
/>
<Button type="submit">Save</Button>
</div>
)}
/>
)}
/>
</div>
)
}

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
},
"dependencies": {
"@dnd-kit/core": "^3.0.0",
"@dnd-kit/sortable": "^3.0.0",
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.7.1",
"@mui/icons-material": "5.15.18",
Expand Down
4 changes: 2 additions & 2 deletions pages/event/[eventId].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { makeSerializable } from "lib/utils"
import Content from "components/content/Content"
import NavDiagram from "components/NavDiagram"
import Title from "components/ui/Title"
import { Event, EventFull } from "lib/types"
import type { Event, EventFull } from "lib/types"
import { basePath } from "lib/basePath"
import { Avatar, Button, Card, Tabs } from "flowbite-react"
import EventProblems from "components/EventProblems"
Expand Down Expand Up @@ -187,7 +187,7 @@ const Event: NextPage<EventProps> = ({ material, event, pageInfo }) => {
))}
<Button onClick={handleAddGroup}>Add Group</Button>
</div>
<Button type="submit">Save</Button>
<Button type="submit">Save Changes</Button>
</Stack>
</form>
)
Expand Down
Loading

0 comments on commit 70b47ca

Please sign in to comment.