-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add DatePicker, TimePicker and LocationSuggestion
- Loading branch information
Pham Nhat Tan
committed
Mar 7, 2023
1 parent
f16dc7b
commit d0217b4
Showing
15 changed files
with
776 additions
and
130 deletions.
There are no files selected for viewing
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
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
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,33 @@ | ||
"use client"; | ||
|
||
import useOnClickOutside from "@/utils/hooks/useOnClickOutside"; | ||
import { format, } from 'date-fns'; | ||
import React from "react"; | ||
import { DayPicker } from 'react-day-picker'; | ||
|
||
const DatePicker = () => { | ||
const ref = React.useRef(null); | ||
const [isOpenPicker, togglePicker] = React.useState<boolean>(false); | ||
const [selected, setSelected] = React.useState<Date>(new Date()); | ||
useOnClickOutside(ref, () => togglePicker(false)); | ||
|
||
return <div className="relative" ref={ref}> | ||
<input className="rounded h-[40px] px-3 w-full placeholder-current" placeholder="Date" | ||
onFocus={ev => togglePicker(true)} | ||
defaultValue={format(selected, "yyyy-MM-dd")} | ||
/> | ||
{isOpenPicker && <div className="absolute rounded bg-white left-0 top-100 mt-1"> | ||
<DayPicker | ||
mode="single" | ||
showOutsideDays | ||
selected={selected} | ||
onSelect={date => { | ||
setSelected(date!); | ||
togglePicker(false); | ||
}} | ||
/> | ||
</div>} | ||
</div> | ||
} | ||
|
||
export default DatePicker; |
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,28 @@ | ||
"use client"; | ||
|
||
import React from "react"; | ||
|
||
type CheckboxProps = { | ||
id: string | ||
name: string | ||
label: string | ||
} | ||
|
||
const Checkbox = (props: CheckboxProps) => { | ||
|
||
return <div className="flex items-center mr-4 mb-2"> | ||
<input type="checkbox" id={props.id} name={props.name} value="yes" className="opacity-0 absolute h-6 w-6" /> | ||
<div className="bg-white border-2 rounded-md border-gray-400 w-6 h-6 flex flex-shrink-0 justify-center items-center focus-within:border-gray-500"> | ||
<svg className="fill-current hidden w-3 h-3 text-gray-600 pointer-events-none" version="1.1" viewBox="0 0 17 12" xmlns="https://www.w3.org/2000/svg"> | ||
<g fill="none" fill-rule="evenodd"> | ||
<g transform="translate(-9 -11)" fill="#942F70" fill-rule="nonzero"> | ||
<path d="m25.576 11.414c0.56558 0.55188 0.56558 1.4439 0 1.9961l-9.404 9.176c-0.28213 0.27529-0.65247 0.41385-1.0228 0.41385-0.37034 0-0.74068-0.13855-1.0228-0.41385l-4.7019-4.588c-0.56584-0.55188-0.56584-1.4442 0-1.9961 0.56558-0.55214 1.4798-0.55214 2.0456 0l3.679 3.5899 8.3812-8.1779c0.56558-0.55214 1.4798-0.55214 2.0456 0z" /> | ||
</g> | ||
</g> | ||
</svg> | ||
</div> | ||
<label htmlFor={props.id} className="ml-3">{props.label}</label> | ||
</div> | ||
} | ||
|
||
export default Checkbox; |
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,28 @@ | ||
"use client"; | ||
|
||
import React from "react"; | ||
|
||
type RadioProps = { | ||
id: string | ||
name: string | ||
label: string | ||
} | ||
|
||
const Radio = (props: RadioProps) => { | ||
|
||
return <div className="flex items-center mr-4 mb-2"> | ||
<input type="radio" id={props.id} name={props.name} value="yes" className="opacity-0 absolute h-6 w-6" /> | ||
<div className="bg-white border-2 rounded-full border-gray-400 w-6 h-6 flex flex-shrink-0 justify-center items-center focus-within:border-gray-500"> | ||
<svg className="fill-current hidden w-3 h-3 text-gray-600 pointer-events-none" version="1.1" viewBox="0 0 17 12" xmlns="https://www.w3.org/2000/svg"> | ||
<g fill="none" fill-rule="evenodd"> | ||
<g transform="translate(-9 -11)" fill="#942F70" fill-rule="nonzero"> | ||
<path d="m25.576 11.414c0.56558 0.55188 0.56558 1.4439 0 1.9961l-9.404 9.176c-0.28213 0.27529-0.65247 0.41385-1.0228 0.41385-0.37034 0-0.74068-0.13855-1.0228-0.41385l-4.7019-4.588c-0.56584-0.55188-0.56584-1.4442 0-1.9961 0.56558-0.55214 1.4798-0.55214 2.0456 0l3.679 3.5899 8.3812-8.1779c0.56558-0.55214 1.4798-0.55214 2.0456 0z" /> | ||
</g> | ||
</g> | ||
</svg> | ||
</div> | ||
<label htmlFor={props.id} className="ml-3 block text-base font-normal text-gray-600">{props.label}</label> | ||
</div> | ||
} | ||
|
||
export default Radio; |
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,90 @@ | ||
"use client"; | ||
|
||
import useDebounce from "@/utils/hooks/useDebounce"; | ||
import useOnClickOutside from "@/utils/hooks/useOnClickOutside"; | ||
import { format, } from 'date-fns'; | ||
import React, { ChangeEvent, useCallback, useEffect, useRef, useState } from "react"; | ||
import { DayPicker } from 'react-day-picker'; | ||
|
||
type Location = { | ||
id: string | ||
lat?: number | ||
long?: number | ||
name: string | ||
address: string | ||
} | ||
|
||
const LocationSuggestion = () => { | ||
const ref = useRef(null); | ||
const [isLoading, toggleLoading] = useState<boolean>(false); | ||
const [suggestions, setSuggestions] = useState<Location[]>([]); | ||
const [isOpenPicker, togglePicker] = useState<boolean>(false); | ||
const [value, setValue] = useState<string>(''); | ||
const debouncedValue = useDebounce<string>(value, 500); | ||
const [selected, setSelected] = useState<Location | null>(null); | ||
|
||
useOnClickOutside(ref, () => togglePicker(false)); | ||
|
||
useEffect(() => { | ||
fetchData(); | ||
}, [debouncedValue]); | ||
|
||
const fetchData = useCallback(() => { | ||
if (value.trim().length > 0 && isOpenPicker) { | ||
toggleLoading(true); | ||
setTimeout(() => { | ||
setSuggestions([ | ||
{ | ||
id: "1", | ||
name: "Chelsea Market", | ||
address: "163 W 20nd Street, Manhattan, NYC" | ||
}, | ||
{ | ||
id: "2", | ||
name: "Coffee Project", | ||
address: "155 7th Ave, New York, NYC" | ||
}, | ||
{ | ||
id: "3", | ||
name: "Slate NY", | ||
address: "54 W 21st St, New York, NYC" | ||
} | ||
]); | ||
toggleLoading(false); | ||
}, 150) | ||
} | ||
}, [value, isOpenPicker]); | ||
|
||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => { | ||
setValue(event.target.value); | ||
setSelected(null); | ||
} | ||
|
||
const handleChangeSelection = (p: Location) => { | ||
setSelected(p); | ||
togglePicker(false); | ||
setValue(p.name); | ||
} | ||
|
||
return <div className="relative w-full" ref={ref}> | ||
<input className="rounded h-[40px] px-3 w-full placeholder-current" placeholder="Location" | ||
onFocus={ev => togglePicker(true)} | ||
value={value} | ||
onChange={handleChange} | ||
/> | ||
{isOpenPicker && <div className="absolute rounded bg-white left-0 top-100 mt-1 w-full max-h-[200px] overflow-y-auto"> | ||
{isLoading ? | ||
<div className="p-2 text-gray-500">Loading...</div> | ||
: | ||
suggestions.length < 1 ? | ||
<div className="p-2">No suggestion!</div> | ||
: <div> | ||
{suggestions.map(e => <div key={e.id} className="p-2 hover:bg-gray-200 cursor-pointer" onClick={() => handleChangeSelection(e)}> | ||
{e.name} - {e.address} | ||
</div>)} | ||
</div>} | ||
</div>} | ||
</div> | ||
} | ||
|
||
export default LocationSuggestion; |
Oops, something went wrong.