Skip to content

Commit

Permalink
Merge branch 'main' into issue/204
Browse files Browse the repository at this point in the history
  • Loading branch information
toririm committed Oct 6, 2024
2 parents 26b7298 + 303b1d2 commit 7c05677
Show file tree
Hide file tree
Showing 18 changed files with 742 additions and 219 deletions.
23 changes: 23 additions & 0 deletions app/components/atoms/Circle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { ClassValue } from "clsx";
import type { ReactNode } from "react";
import { cn } from "~/lib/utils";

type props = {
focus: boolean;
children: ReactNode;
className?: ClassValue;
};

const Circle = ({ focus, children, className }: props) => (
<div
className={cn(
"flex h-12 w-12 items-center justify-center rounded-full border-2 border-stone-500 font-extrabold text-2xl text-stone-500",
focus && "bg-stone-950 text-white",
className,
)}
>
{children}
</div>
);

export { Circle };
4 changes: 2 additions & 2 deletions app/components/functional/useFocusRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { useEffect, useRef } from "react";
* @param focus フォーカスを当てるかどうか
* @returns
*/
const useFocusRef = (focus: boolean) => {
const DOMRef = useRef<HTMLInputElement>(null);
const useFocusRef = <T extends HTMLElement>(focus: boolean) => {
const DOMRef = useRef<T>(null);

useEffect(() => {
if (focus) {
Expand Down
4 changes: 2 additions & 2 deletions app/components/functional/useInputStatus.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useCallback, useMemo, useState } from "react";

const InputStatusList = [
"discount",
"items",
"received",
"discount",
"description",
"received",
"submit",
] as const;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ type props = InputProps & {
};

/**
* focus が true のときに自動でフォーカスを当てるテキストボックス
* focus が true のときに自動でフォーカスを当てる input
*/
const AttractiveTextBox = ({ focus, onTextSet, ...props }: props) => {
const AttractiveInput = ({ focus, onTextSet, ...props }: props) => {
const [text, setText] = useState("");
const DOMRef = useFocusRef(focus);
const DOMRef = useFocusRef<HTMLInputElement>(focus);

const onChangeHandler: ChangeEventHandler<HTMLInputElement> = useCallback(
(event) => setText(event.target.value),
Expand All @@ -39,4 +39,4 @@ const AttractiveTextBox = ({ focus, onTextSet, ...props }: props) => {
);
};

export { AttractiveTextBox };
export { AttractiveInput };
42 changes: 42 additions & 0 deletions app/components/molecules/AttractiveTextArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {
type ChangeEventHandler,
useCallback,
useEffect,
useState,
} from "react";
import { useFocusRef } from "../functional/useFocusRef";
import { Textarea, type TextareaProps } from "../ui/textarea";

type props = TextareaProps & {
onTextSet: (text: string) => void;
focus: boolean;
};

/**
* focus が true のときに自動でフォーカスを当てる textarea
*/
const AttractiveTextArea = ({ focus, onTextSet, ...props }: props) => {
const [text, setText] = useState("");
const DOMRef = useFocusRef<HTMLTextAreaElement>(focus);

const onChangeHandler: ChangeEventHandler<HTMLTextAreaElement> = useCallback(
(event) => setText(event.target.value),
[],
);

useEffect(() => {
onTextSet(text);
}, [text, onTextSet]);

return (
<Textarea
value={text}
onChange={onChangeHandler}
ref={DOMRef}
disabled={!focus}
{...props}
/>
);
};

export { AttractiveTextArea };
28 changes: 28 additions & 0 deletions app/components/molecules/InputHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { cn } from "~/lib/utils";
import { Circle } from "../atoms/Circle";

type props = {
title: string;
focus: boolean;
number: number;
};

const InputHeader = ({ title, focus, number }: props) => {
return (
<div className="flex items-center p-3">
<Circle focus={focus} className="flex-initial">
{number}
</Circle>
<h2
className={cn(
"pl-5 font-semibold text-stone-500 text-xl",
focus && "text-black",
)}
>
{title}
</h2>
</div>
);
};

export { InputHeader };
57 changes: 57 additions & 0 deletions app/components/organisms/ConfirmDrawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { type ComponentProps, useEffect, useRef } from "react";
import type { Drawer as DrawerPrimitive } from "vaul";
import { Button } from "../ui/button";
import {
Drawer,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerTitle,
} from "../ui/drawer";

const sleep = (time: number) =>
new Promise((resolve) => setTimeout(resolve, time)); //timeはミリ秒

type props = ComponentProps<typeof DrawerPrimitive.Root> & {
focus: boolean;
children: React.ReactNode;
onConfirm: () => void;
};

const ConfirmDrawer = ({ children, focus, onConfirm, ...props }: props) => {
const buttonRef = useRef<HTMLButtonElement>(null);

useEffect(() => {
console.log("use eefect");
const wait = async () => {
await sleep(3000);
};
wait();
if (focus) {
buttonRef.current?.focus();
console.log("focue executed");
}
}, [focus]);

return (
<Drawer open={focus} {...props}>
<DrawerContent>
<DrawerHeader>
<DrawerTitle className="text-center">送信しますか?</DrawerTitle>
</DrawerHeader>
{children}
<DrawerFooter className="flex items-center justify-center">
<Button
ref={buttonRef}
onClick={onConfirm}
className="w-1/2 bg-orange-600"
>
送信
</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
);
};

export { ConfirmDrawer };
49 changes: 35 additions & 14 deletions app/components/organisms/DiscountInput.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { CheckCircledIcon, CrossCircledIcon } from "@radix-ui/react-icons";
import {
type ComponentPropsWithoutRef,
useEffect,
Expand Down Expand Up @@ -34,7 +35,7 @@ const DiscountInput = ({
...props
}: props) => {
const [discountOrderId, setDiscountOrderId] = useState("");
const ref = useFocusRef(focus);
const ref = useFocusRef<HTMLInputElement>(focus);

const isComplete = useMemo(
() => discountOrderId.length === 3,
Expand All @@ -60,21 +61,41 @@ const DiscountInput = ({
}, [isComplete, discountOrder, onDiscountOrderFind, onDiscountOrderRemoved]);

return (
<div>
<p>割引券番号</p>
<ThreeDigitsInput
ref={ref}
value={discountOrderId}
onChange={(value) => setDiscountOrderId(value)}
disabled={!focus}
{...props}
/>
<div className="">
<div className="flex justify-center p-6">
<div className="">
<p className="pb-1 text-sm">番号</p>
<ThreeDigitsInput
ref={ref}
value={discountOrderId}
onChange={(value) => setDiscountOrderId(value)}
disabled={!focus}
{...props}
/>
</div>
</div>
<p>
{!isComplete && "3桁の割引券番号を入力してください"}
{!isComplete && (
<div className="flex items-center">
{/* <ExclamationTriangleIcon className="mr-1 stroke-stone-400" /> */}
<p className="text-sm text-stone-400">3桁すべて入力してください</p>
</div>
)}
{isComplete &&
(discountOrder instanceof OrderEntity
? `有効杯数: ${lastPurchasedCups}`
: "見つかりません")}
(discountOrder instanceof OrderEntity ? (
<div className="flex items-center">
<CheckCircledIcon className="mr-1 h-5 w-5 stroke-green-700" />
<p className="flex items-center">
<span className="mr-1 text-lg">{lastPurchasedCups}</span>
杯分
</p>
</div>
) : (
<div className="flex items-center">
<CrossCircledIcon className="mr-1 h-5 w-5 stroke-red-700" />
<p className="flex items-center">無効な番号</p>
</div>
))}
</p>
</div>
);
Expand Down
66 changes: 48 additions & 18 deletions app/components/organisms/ItemAssign.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCallback, useEffect, useState } from "react";
import { Pencil2Icon } from "@radix-ui/react-icons";
import { useCallback, useEffect, useMemo, useState } from "react";
import type { WithId } from "~/lib/typeguard";
import { cn } from "~/lib/utils";
import { type ItemEntity, type2label } from "~/models/item";
Expand All @@ -22,7 +23,7 @@ type props = {
const ItemAssign = ({ item, idx, mutateItem, focus, highlight }: props) => {
const [assignee, setAssinee] = useState<string | null>(null);

const assignInputRef = useFocusRef(focus);
const assignInputRef = useFocusRef<HTMLInputElement>(focus);

const saveAssignInput = useCallback(() => {
mutateItem(idx, (prev) => {
Expand All @@ -39,24 +40,53 @@ const ItemAssign = ({ item, idx, mutateItem, focus, highlight }: props) => {
}
}, [focus, saveAssignInput]);

const assignView = useMemo(() => {
if (item.assignee) return item.assignee;
return highlight ? "Enterで入力" : " ";
}, [highlight, item.assignee]);

return (
<div className={cn("grid grid-cols-2", highlight && "bg-orange-500")}>
<p className="font-bold text-lg">{idx + 1}</p>
<div>
<p>{item.name}</p>
<p>{item.price}</p>
<p>{type2label[item.type]}</p>
{focus ? (
<Input
ref={assignInputRef}
value={assignee ?? ""}
onChange={(e) => setAssinee(e.target.value || null)}
placeholder="指名"
/>
) : (
<p>{item.assignee ?? "指名なし"}</p>
)}
<div
className={cn(
"grid grid-cols-6 border-white border-l-2",
highlight && "border-orange-600",
)}
>
<div className="col-span-5 flex items-center">
<p className="flex-none p-3 font-bold font-mono text-lg">{idx + 1}</p>
<div className="flex-1">
<p className="font-bold text-lg">{item.name}</p>
<p className="text-stone-500 text-xs">{type2label[item.type]}</p>
<div className="flex justify-end">
{focus ? (
<Input
ref={assignInputRef}
value={assignee ?? ""}
onChange={(e) => setAssinee(e.target.value || null)}
placeholder="指名"
className="h-6 w-1/2 border-stone-300 border-b-2 text-sm"
/>
) : (
<div
className={cn(
"flex w-1/2 items-center border-stone-300 border-b-2",
highlight && "border-stone-950",
)}
>
{highlight && (
<Pencil2Icon className="w-1/6 stroke-stone-400 pr-1" />
)}
<p className="w-5/6 flex-none text-sm text-stone-400">
{assignView}
</p>
</div>
)}
</div>
</div>
</div>
<p className="flex items-center justify-end text-right">
&yen;{item.price}
</p>
</div>
);
};
Expand Down
Loading

0 comments on commit 7c05677

Please sign in to comment.