-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: added time selection for availability * feat: added time selection for availability * prettierignore update
- Loading branch information
Showing
7 changed files
with
1,703 additions
and
2,096 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,4 @@ | |
README.md | ||
package-lock.json | ||
next-env.d.ts | ||
pnpm-lock.yaml |
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,49 @@ | ||
import { useState } from 'react'; | ||
import TimeSelection from '@/components/TimeSelection/TimeSelection'; | ||
import COLORS from '@/styles/colors'; | ||
import { H6, SMALL } from '@/styles/text'; | ||
import { AddTime, Bar, Container, TimeList, Times } from './styles'; | ||
|
||
export default function DateTimeSelection({ date }: { date: Date }) { | ||
const [timeList, setTimeList] = useState([ | ||
<Times key={0}> | ||
{/* initialize at 9 am / 5 pm */} | ||
<TimeSelection minutes={9 * 60} /> | ||
<H6 $color={COLORS.gray8}> - </H6> | ||
<TimeSelection minutes={17 * 60} /> | ||
</Times>, | ||
]); | ||
|
||
const onAddBtnClick = () => { | ||
setTimeList( | ||
timeList.concat( | ||
<Times> | ||
{/* initialize at 9 am / 5 pm */} | ||
<TimeSelection minutes={9 * 60} /> | ||
<H6 $color={COLORS.gray8}> - </H6> | ||
<TimeSelection minutes={17 * 60} /> | ||
</Times>, | ||
), | ||
); | ||
}; | ||
|
||
return ( | ||
<Container> | ||
<H6 $fontWeight={500}> | ||
{date.toLocaleDateString('en-US', { | ||
weekday: 'short', | ||
month: 'long', | ||
day: 'numeric', | ||
year: 'numeric', | ||
})} | ||
</H6> | ||
<Bar /> | ||
<TimeList> {timeList}</TimeList> | ||
<AddTime onClick={() => onAddBtnClick()}> | ||
<SMALL $color={COLORS.lilac8} $fontWeight={400}> | ||
add time | ||
</SMALL> | ||
</AddTime> | ||
</Container> | ||
); | ||
} |
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,35 @@ | ||
import styled from 'styled-components'; | ||
import COLORS from '@/styles/colors'; | ||
|
||
export const Container = styled.div` | ||
padding: 2rem; | ||
`; | ||
|
||
export const Bar = styled.hr` | ||
height: 1px; | ||
color: ${COLORS.gray6}; | ||
background: ${COLORS.gray6}; | ||
font-size: 0; | ||
border: 0; | ||
margin-top: 0.5rem; | ||
margin-bottom: 1rem; | ||
`; | ||
|
||
export const Times = styled.div` | ||
display: flex; | ||
flex-direction: horizontal; | ||
gap: 0.5rem; | ||
align-items: center; | ||
`; | ||
|
||
export const AddTime = styled.button` | ||
all: unset; | ||
padding-top: 1rem; | ||
padding-bottom: 1rem; | ||
`; | ||
|
||
export const TimeList = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
gap: 0.5rem; | ||
`; |
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,91 @@ | ||
import React from 'react'; | ||
import { CheckIcon, ChevronDownIcon } from '@radix-ui/react-icons'; | ||
import * as ScrollArea from '@radix-ui/react-scroll-area'; | ||
import * as Select from '@radix-ui/react-select'; | ||
import classnames from 'classnames'; | ||
import { Container, Content } from './styles'; | ||
|
||
export default function TimeSelection({ minutes }: { minutes: number }) { | ||
const minutesToFormatted = (minutes: number) => { | ||
const hours = Math.floor(minutes / 60); | ||
const mins = minutes % 60; | ||
const period = hours >= 12 ? 'PM' : 'AM'; | ||
const formattedHours = hours > 12 ? hours - 12 : hours; | ||
return `${formattedHours}:${mins.toString().padStart(2, '0')} ${period}`; | ||
}; | ||
|
||
const generateTimeSlots = () => { | ||
const times = []; | ||
const startTime = 9 * 60; // 9:00 AM in minutes | ||
const endTime = 20 * 60; // 5:00 PM in minutes | ||
|
||
for (let minutes = startTime; minutes <= endTime; minutes += 30) { | ||
times.push([minutes.toString(), minutesToFormatted(minutes)]); | ||
} | ||
|
||
return times; | ||
}; | ||
|
||
const times = generateTimeSlots(); | ||
|
||
return ( | ||
<Container> | ||
<Select.Root defaultValue={minutes.toString()}> | ||
<Select.Trigger className="SelectTrigger" aria-label="Food"> | ||
<Select.Value placeholder={minutesToFormatted(minutes)} /> | ||
<Select.Icon className="SelectIcon"> | ||
<ChevronDownIcon /> | ||
</Select.Icon> | ||
</Select.Trigger> | ||
<Select.Portal> | ||
<Content> | ||
<Select.Content className="SelectContent"> | ||
<ScrollArea.Root className="Scroll" type="auto"> | ||
<Select.Viewport asChild className="SelectViewport"> | ||
<ScrollArea.Viewport className="ScrollViewport"> | ||
<Select.Group className="group"> | ||
{times.map((time, i) => { | ||
const minutes = time[0]; | ||
const formattedTime = time[1]; | ||
return ( | ||
<SelectItem key={i} value={minutes}> | ||
{formattedTime} | ||
</SelectItem> | ||
); | ||
})} | ||
</Select.Group> | ||
</ScrollArea.Viewport> | ||
</Select.Viewport> | ||
</ScrollArea.Root> | ||
</Select.Content> | ||
</Content> | ||
</Select.Portal> | ||
</Select.Root> | ||
</Container> | ||
); | ||
} | ||
|
||
interface SelectItemProps | ||
extends React.ComponentPropsWithoutRef<typeof Select.Item> { | ||
children: React.ReactNode; | ||
className?: string; | ||
} | ||
|
||
const SelectItem = React.forwardRef<HTMLDivElement, SelectItemProps>( | ||
({ children, className, ...props }, forwardedRef) => { | ||
return ( | ||
<Select.Item | ||
className={classnames('SelectItem', className)} | ||
{...props} | ||
ref={forwardedRef} | ||
> | ||
<Select.ItemIndicator className="SelectItemIndicator"> | ||
<CheckIcon /> | ||
</Select.ItemIndicator> | ||
<Select.ItemText>{children}</Select.ItemText> | ||
</Select.Item> | ||
); | ||
}, | ||
); | ||
|
||
SelectItem.displayName = 'test'; |
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,102 @@ | ||
import styled from 'styled-components'; | ||
import COLORS from '@/styles/colors'; | ||
|
||
export const Container = styled.div` | ||
button { | ||
all: unset; | ||
} | ||
.SelectTrigger { | ||
display: inline-flex; | ||
align-items: center; | ||
justify-content: center; | ||
border-radius: 8px; | ||
padding: 0 15px; | ||
font-size: 13px; | ||
line-height: 1; | ||
height: 35px; | ||
gap: 5px; | ||
background-color: white; | ||
color = ${COLORS.gray11}; | ||
border: 1px solid ${COLORS.gray8}; | ||
} | ||
.SelectTrigger:hover { | ||
background-color: ${COLORS.rose5}; | ||
} | ||
.SelectItem[data-disabled] { | ||
pointer-events: none; | ||
} | ||
.SelectLabel { | ||
padding: 0 25px; | ||
font-size: 12px; | ||
line-height: 25px; | ||
color = ${COLORS.gray8}; | ||
} | ||
`; | ||
|
||
export const Content = styled.div` | ||
.Scroll { | ||
overflow: scroll; | ||
height: 200px; | ||
background-color: white; | ||
border: 1px solid ${COLORS.rose7}; | ||
border-radius: 8px; | ||
box-shadow: | ||
0px 10px 38px -10px rgba(22, 23, 24, 0.35), | ||
0px 10px 20px -15px rgba(22, 23, 24, 0.2); | ||
} | ||
.ScrollViewPort { | ||
width: 100%; | ||
height: 100%; | ||
} | ||
.SelectContent { | ||
} | ||
.SelectScrollButton { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
height: 25px; | ||
background-color: white; | ||
color: var(--violet-11); | ||
cursor: default; | ||
} | ||
.SelectItem { | ||
font-size: 13px; | ||
line-height: 1; | ||
color: black; | ||
border-radius: 8px; | ||
display: flex; | ||
align-items: center; | ||
height: 30px; | ||
padding: 0 25px 0 25px; | ||
position: relative; | ||
user-select: none; | ||
color = ${COLORS.gray11}; | ||
} | ||
.SelectItem[data-highlighted] { | ||
outline: none; | ||
background-color: ${COLORS.rose5}; | ||
cursor: default; | ||
} | ||
.SelectViewport { | ||
padding: 5px; | ||
} | ||
.SelectItemIndicator { | ||
position: absolute; | ||
left: 0; | ||
width: 25px; | ||
display: inline-flex; | ||
align-items: center; | ||
justify-content: center; | ||
} | ||
`; |
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
Oops, something went wrong.