-
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat/13: components for setting schedule on a task
- Loading branch information
Showing
4 changed files
with
308 additions
and
0 deletions.
There are no files selected for viewing
120 changes: 120 additions & 0 deletions
120
src/scenes/sharedTaskComponents/PickUpAndDeliverSchedule.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import * as React from "react"; | ||
import { | ||
Box, | ||
Button, | ||
Dialog, | ||
DialogActions, | ||
DialogContent, | ||
DialogTitle, | ||
Paper, | ||
Stack, | ||
Typography, | ||
} from "@mui/material"; | ||
import TimeRelationPicker from "./TimeRelationPicker"; | ||
import ScheduledDatePicker from "./ScheduledDatePicker"; | ||
|
||
export enum ScheduledDatePickerOption { | ||
TODAY = "Today", | ||
TOMORROW = "Tomorrow", | ||
CUSTOM = "Custom", | ||
} | ||
|
||
const PickUpAndDeliverSchedule = () => { | ||
const [dialogOpen, setDialogOpen] = React.useState(false); | ||
|
||
const [selectionPickUpState, setSelectionPickUpState] = | ||
React.useState<ScheduledDatePickerOption | null>(null); | ||
const [customPickUpDate, setCustomPickUpDate] = React.useState<Date | null>( | ||
null | ||
); | ||
|
||
const handleSetPickUpState = (selection: ScheduledDatePickerOption) => { | ||
if (selectionPickUpState === selection) setSelectionPickUpState(null); | ||
else setSelectionPickUpState(selection); | ||
if ( | ||
selection === ScheduledDatePickerOption.CUSTOM && | ||
customPickUpDate === null | ||
) | ||
setCustomPickUpDate(new Date()); | ||
}; | ||
|
||
const [selectionDropOffState, setSelectionDropOffState] = | ||
React.useState<ScheduledDatePickerOption | null>(null); | ||
const [customDropOffDate, setCustomDropOffDate] = | ||
React.useState<Date | null>(null); | ||
|
||
const handleSetDropOffState = (selection: ScheduledDatePickerOption) => { | ||
if (selectionDropOffState === selection) setSelectionDropOffState(null); | ||
else setSelectionDropOffState(selection); | ||
if ( | ||
selection === ScheduledDatePickerOption.CUSTOM && | ||
customDropOffDate === null | ||
) | ||
setCustomDropOffDate(new Date()); | ||
}; | ||
|
||
return ( | ||
<> | ||
<Stack | ||
direction="row" | ||
sx={{ width: "100%" }} | ||
justifyContent="space-between" | ||
alignItems="center" | ||
> | ||
<Typography>No scheduled set.</Typography> | ||
<Button onClick={() => setDialogOpen(true)}> | ||
Add schedule | ||
</Button> | ||
</Stack> | ||
<Dialog open={dialogOpen}> | ||
<DialogTitle>Add schedule</DialogTitle> | ||
<DialogContent> | ||
<Stack spacing={2}> | ||
<Paper | ||
sx={{ | ||
display: "flex", | ||
gap: 1, | ||
flexDirection: "column", | ||
padding: 2, | ||
borderRadius: "1em", | ||
}} | ||
> | ||
<Typography variant="h6">Pick up</Typography> | ||
<ScheduledDatePicker | ||
onSelectOption={handleSetPickUpState} | ||
option={selectionPickUpState} | ||
onSelectCustomDate={setCustomPickUpDate} | ||
customDate={customPickUpDate} | ||
/> | ||
{selectionPickUpState && <TimeRelationPicker />} | ||
</Paper> | ||
<Paper | ||
sx={{ | ||
display: "flex", | ||
gap: 1, | ||
flexDirection: "column", | ||
padding: 2, | ||
borderRadius: "1em", | ||
}} | ||
> | ||
<Typography variant="h6">Drop off</Typography> | ||
<ScheduledDatePicker | ||
onSelectOption={handleSetDropOffState} | ||
option={selectionDropOffState} | ||
onSelectCustomDate={setCustomDropOffDate} | ||
customDate={customDropOffDate} | ||
/> | ||
{selectionDropOffState && <TimeRelationPicker />} | ||
</Paper> | ||
</Stack> | ||
</DialogContent> | ||
<DialogActions> | ||
<Button onClick={() => setDialogOpen(false)}>Cancel</Button> | ||
<Button onClick={() => setDialogOpen(false)}>OK</Button> | ||
</DialogActions> | ||
</Dialog> | ||
</> | ||
); | ||
}; | ||
|
||
export default PickUpAndDeliverSchedule; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import * as React from "react"; | ||
import { Chip, Box, TextField, Stack } from "@mui/material"; | ||
import { DatePicker } from "@mui/lab"; | ||
import { ScheduledDatePickerOption } from "./PickUpAndDeliverSchedule"; | ||
|
||
type ScheduledDatePickerProps = { | ||
onSelectOption: (selection: ScheduledDatePickerOption) => void; | ||
option: ScheduledDatePickerOption | null; | ||
onSelectCustomDate: (date: Date | null) => void; | ||
customDate?: Date | null; | ||
}; | ||
|
||
const ScheduledDatePicker: React.FC<ScheduledDatePickerProps> = ({ | ||
onSelectOption, | ||
option, | ||
onSelectCustomDate, | ||
customDate, | ||
}) => { | ||
const isToday = option === ScheduledDatePickerOption.TODAY; | ||
const isTomorrow = option === ScheduledDatePickerOption.TOMORROW; | ||
const isCustom = option === ScheduledDatePickerOption.CUSTOM; | ||
|
||
const handleSetToday = () => { | ||
onSelectOption(ScheduledDatePickerOption.TODAY); | ||
}; | ||
|
||
const handleSetTomorrow = () => { | ||
onSelectOption(ScheduledDatePickerOption.TOMORROW); | ||
}; | ||
|
||
const handleSetCustom = () => { | ||
onSelectOption(ScheduledDatePickerOption.CUSTOM); | ||
}; | ||
|
||
return ( | ||
<Stack spacing={1}> | ||
<Box sx={{ display: "flex", direction: "row", gap: 1 }}> | ||
<Chip | ||
variant={isToday ? "filled" : "outlined"} | ||
label="Today" | ||
onClick={handleSetToday} | ||
color={isToday ? "primary" : "default"} | ||
/> | ||
<Chip | ||
variant={isTomorrow ? "filled" : "outlined"} | ||
label="Tomorrow" | ||
onClick={handleSetTomorrow} | ||
color={isTomorrow ? "primary" : "default"} | ||
/> | ||
<Chip | ||
variant={isCustom ? "filled" : "outlined"} | ||
color={isCustom ? "primary" : "default"} | ||
label="Custom" | ||
onClick={handleSetCustom} | ||
/> | ||
</Box> | ||
{isCustom && ( | ||
<DatePicker | ||
inputFormat={"dd/MM/yyyy"} | ||
value={customDate} | ||
onChange={onSelectCustomDate} | ||
renderInput={(params) => <TextField {...params} />} | ||
/> | ||
)} | ||
</Stack> | ||
); | ||
}; | ||
|
||
export default ScheduledDatePicker; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import React, { useState } from "react"; | ||
import TextField from "@mui/material/TextField"; | ||
import Autocomplete from "@mui/material/Autocomplete"; | ||
|
||
type TimePickerBasicProps = { | ||
value: string; | ||
onChange: (value: string) => void; | ||
isValid: boolean; | ||
}; | ||
|
||
const TimePickerBasic: React.FC<TimePickerBasicProps> = ({ | ||
value, | ||
onChange, | ||
isValid, | ||
}) => { | ||
// Generate time options (same as before) | ||
const timeOptions = generateTimeOptions(); | ||
|
||
const handleInputChange = (_: any, newInputValue: string) => { | ||
// Regular expression to allow only numbers and colons, with a maximum length of 5 | ||
const validInput = newInputValue.replace(/[^0-9:]/g, "").slice(0, 5); | ||
onChange(validInput); | ||
}; | ||
|
||
return ( | ||
<Autocomplete | ||
fullWidth | ||
freeSolo | ||
id="time-picker-basic" | ||
options={timeOptions} | ||
getOptionLabel={(option) => option} | ||
value={value} | ||
inputValue={value} // Make sure inputValue is controlled | ||
onInputChange={handleInputChange} | ||
onChange={(_, newValue) => { | ||
if (typeof newValue === "string") { | ||
onChange(newValue); | ||
} | ||
}} | ||
renderInput={(params) => ( | ||
<TextField | ||
{...params} | ||
helperText={!isValid ? "Invalid time" : ""} | ||
error={!isValid} | ||
label="Time" | ||
variant="outlined" | ||
/> | ||
)} | ||
/> | ||
); | ||
}; | ||
|
||
// Helper function to generate time options | ||
function generateTimeOptions() { | ||
const options = []; | ||
for (let hour = 0; hour < 24; hour++) { | ||
for (let minute = 0; minute < 60; minute += 30) { | ||
const timeString = `${hour.toString().padStart(2, "0")}:${minute | ||
.toString() | ||
.padStart(2, "0")}`; | ||
options.push(timeString); // Store time strings directly in the array | ||
} | ||
} | ||
return options; | ||
} | ||
|
||
export default TimePickerBasic; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import * as React from "react"; | ||
import MenuItem from "@mui/material/MenuItem"; | ||
import FormControl from "@mui/material/FormControl"; | ||
import Select, { SelectChangeEvent } from "@mui/material/Select"; | ||
import * as models from "../../models"; | ||
import { Stack } from "@mui/material"; | ||
import TimePickerBasic from "./TimePickerBasic"; | ||
|
||
const TimeRelationPicker = () => { | ||
const [relation, setRelation] = React.useState<models.TimeRelation>( | ||
models.TimeRelation.ANYTIME | ||
); | ||
const [time, setTime] = React.useState("10:00"); | ||
|
||
const handleChange = (event: SelectChangeEvent) => { | ||
setRelation(event.target.value as models.TimeRelation); | ||
}; | ||
|
||
const isValidTime = (time: string) => { | ||
const [hours, minutes] = time | ||
.split(":") | ||
.map((value) => parseInt(value)); | ||
return hours >= 0 && hours < 24 && minutes >= 0 && minutes < 60; | ||
}; | ||
|
||
const isValid = isValidTime(time); | ||
|
||
const handleChangeTime = (value: string) => { | ||
setTime(value); | ||
}; | ||
|
||
return ( | ||
<Stack spacing={1} direction="row" sx={{ minWidth: 340 }}> | ||
<FormControl fullWidth> | ||
<Select value={relation} onChange={handleChange}> | ||
{Object.values(models.TimeRelation).map((timeRelation) => ( | ||
<MenuItem value={timeRelation}>{timeRelation}</MenuItem> | ||
))} | ||
</Select> | ||
</FormControl> | ||
{relation !== models.TimeRelation.ANYTIME && ( | ||
<TimePickerBasic | ||
isValid={isValid} | ||
onChange={handleChangeTime} | ||
value={time} | ||
/> | ||
)} | ||
</Stack> | ||
); | ||
}; | ||
|
||
export default TimeRelationPicker; |