Skip to content

Commit

Permalink
�inv-47 UI 개선점 적용 (#14)
Browse files Browse the repository at this point in the history
* feat: bottom sheet 구현

* feat: data fetching function parameters reason값 option으로 변경

* feat: bottom sheet 스타일링 적용

* feat: bottom sheet 스타일링 적용

* feat: 디자인 요건에 맞춘 이미지 변경

* fix: build시 sheet 컴포넌트 누락건 해결

* chore: 불필요한 코드 제거

* style: 디자인 요건 반영

* feat: dimmed 기능 추가 이에 따른 불필요한 이미지 제거

* fix: 초기 bottom sheet mount시, 모든 radio가 dimmed 되어있는 현상 수정

* feat: ut main에 bottom sheet 적용

* feat: aria-describedby 추가

* feat: ui 개선 반영
  • Loading branch information
xilucks authored Jul 26, 2024
1 parent 1a93b0b commit 2bc77c8
Showing 1 changed file with 119 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"use client";

import { useForm } from "@tanstack/react-form";
import { useCallback, useEffect, useRef, useState } from "react";
import ImageRadio from "~/app/(playground)/playground/bottom-sheet/_components/image-radio";
import { Button } from "~/components/ui/button";
import { Input } from "~/components/ui/input";
import { Label } from "~/components/ui/label";

import {
Sheet,
SheetClose,
SheetContent,
SheetHeader,
SheetTitle,
Expand All @@ -21,6 +21,7 @@ import AttendanceTrueDefault from "~/assets/attendance/attendance-true-deafult.s
import { createInvitationResponses } from "~/lib/db/schema/invitation_response.query";

export default function BottomSheet() {
const [open, setOpen] = useState(false);
const form = useForm({
defaultValues: {
name: "",
Expand All @@ -39,22 +40,79 @@ export default function BottomSheet() {
border: 0,
},
});
setOpen(false);
},
});

const sheetContentRef = useRef<HTMLDivElement | null>(null);
const startY = useRef<number | null>(null);
const scrollStartY = useRef<number>(0);
const [isDragging, setIsDragging] = useState(false);

useEffect(() => {
const preventDefault = (e: Event) => {
if (isDragging) {
e.preventDefault();
}
};

document.body.addEventListener("touchmove", preventDefault, {
passive: false,
});

return () => {
document.body.removeEventListener("touchmove", preventDefault);
};
}, [isDragging]);

const handleTouchStart = useCallback((e: React.TouchEvent) => {
startY.current = e.touches[0].clientY;
scrollStartY.current = window.scrollY;
}, []);

const handleTouchMove = useCallback((e: React.TouchEvent) => {
if (startY.current === null || !sheetContentRef.current) return;

const currentY = e.touches[0].clientY;
const deltaY = currentY - startY.current;

if (deltaY > 0 && window.scrollY <= scrollStartY.current) {
setIsDragging(true);
sheetContentRef.current!.style.transform = `translateY(${deltaY}px)`;
sheetContentRef.current!.style.transition = "none";
} else {
setIsDragging(false);
}
}, []);

const handleTouchEnd = useCallback(
(e: React.TouchEvent) => {
if (startY.current === null || !sheetContentRef.current) return;

const endY = e.changedTouches[0].clientY;
const deltaY = endY - startY.current;

sheetContentRef.current!.style.transform = "";
sheetContentRef.current!.style.transition = "";

if (deltaY > 100 && isDragging) {
setOpen(false);
}

setIsDragging(false);
startY.current = null;
},
[isDragging],
);

return (
<Sheet key={"bottom"}>
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>
<div
className={
"fixed bottom-0 left-0 right-0 mx-auto h-[127px] w-full max-w-2xl px-4 py-8"
}
>
<div className="fixed bottom-0 left-0 right-0 mx-auto h-[127px] w-full max-w-2xl px-4 py-8">
<Button
variant="outline"
className={
"h-full w-full rounded-xl border-none bg-[#5E8AFF] text-lg font-bold text-white"
}
className="h-full w-full rounded-xl border-none bg-[#5E8AFF] text-lg font-bold text-white"
onClick={() => setOpen(true)}
>
세션 참여 조사하기
</Button>
Expand All @@ -64,6 +122,10 @@ export default function BottomSheet() {
side="bottom"
className="fixed w-full flex-col space-y-10 rounded-t-[32px] border-none bg-[#1A1A1A] pb-0 pt-10 text-white"
aria-describedby={"세션참여 조사 Form"}
ref={sheetContentRef}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
>
<div className="absolute left-1/2 top-4 -translate-x-1/2 transform">
<div className="h-1 w-10 rounded-full bg-[#EDEDED]"></div>
Expand Down Expand Up @@ -91,15 +153,13 @@ export default function BottomSheet() {
</Label>
<form.Field name="name">
{(field) => (
<>
<Input
onChange={(event) =>
field.handleChange(event.target.value)
}
value={field.state.value}
className="col-span-3 h-[50px] rounded-xl border-[#3C3C3C] bg-[#222222] focus:border-[#5E8AFF]"
/>
</>
<Input
onChange={(event) =>
field.handleChange(event.target.value)
}
value={field.state.value}
className="col-span-3 h-[50px] rounded-xl border-[#3C3C3C] bg-[#222222] text-base focus:border-[#5E8AFF]"
/>
)}
</form.Field>
</div>
Expand All @@ -108,55 +168,51 @@ export default function BottomSheet() {
<div className="flex flex-row items-center gap-4">
<form.Field name="attendance">
{(field) => (
<>
<ImageRadio
name={field.name}
value={field.state.value}
onChange={(event) => {
field.handleChange(
event.target.value as "true" | "false" | "",
);
}}
>
<ImageRadio.Option
imageUrl={AttendanceTrueDefault}
value={"true"}
text={"참여"}
checked={field.state.value === "true"}
/>
<ImageRadio.Option
imageUrl={AttendanceFalseDefault}
value={"false"}
text={"불참"}
checked={field.state.value === "false"}
/>
</ImageRadio>
</>
<ImageRadio
name={field.name}
value={field.state.value}
onChange={(event) => {
field.handleChange(
event.target.value as "true" | "false" | "",
);
}}
>
<ImageRadio.Option
imageUrl={AttendanceTrueDefault}
value={"true"}
text={"참여"}
checked={field.state.value === "true"}
/>
<ImageRadio.Option
imageUrl={AttendanceFalseDefault}
value={"false"}
text={"불참"}
checked={field.state.value === "false"}
/>
</ImageRadio>
)}
</form.Field>
</div>
</div>
</div>
<SheetClose asChild>
<div className={"h-[127px] py-[34px]"}>
<form.Subscribe selector={(state) => state}>
{({ isValid, isSubmitting, errors, values }) => {
const isFormComplete =
isValid && values.name && values.attendance;
return (
<Button
type="submit"
variant="outline"
disabled={!isFormComplete || isSubmitting}
className={`h-full w-full rounded-xl border-none bg-[#5E8AFF] text-lg font-bold text-white disabled:bg-[#D5D7D9]`}
>
제출하기
</Button>
);
}}
</form.Subscribe>
</div>
</SheetClose>
<div className={"h-[127px] py-[34px]"}>
<form.Subscribe selector={(state) => state}>
{({ isValid, isSubmitting, values }) => {
const isFormComplete =
isValid && values.name && values.attendance;
return (
<Button
type="submit"
variant="outline"
disabled={!isFormComplete || isSubmitting}
className={`h-full w-full rounded-xl border-none bg-[#5E8AFF] text-lg font-bold text-white disabled:bg-[#D5D7D9]`}
>
제출하기
</Button>
);
}}
</form.Subscribe>
</div>
</form>
</SheetContent>
</Sheet>
Expand Down

0 comments on commit 2bc77c8

Please sign in to comment.