Skip to content

Commit

Permalink
Merge pull request #7 from toririm/feature/items
Browse files Browse the repository at this point in the history
アイテムページを作成
  • Loading branch information
toririm authored Aug 7, 2024
2 parents b66ff25 + cccf37c commit df3dcd7
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 2 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"editor.formatOnSaveMode": "file",
"editor.codeActionsOnSave": {
"source.organizeImports": "always"
}
},
"editor.tabSize": 2
}
25 changes: 25 additions & 0 deletions app/components/ui/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as React from "react";

import { cn } from "~/lib/utils";

export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}

const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
ref={ref}
{...props}
/>
);
},
);
Input.displayName = "Input";

export { Input };
24 changes: 24 additions & 0 deletions app/components/ui/label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from "react";
import * as LabelPrimitive from "@radix-ui/react-label";
import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "~/lib/utils";

const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
);

const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
));
Label.displayName = LabelPrimitive.Root.displayName;

export { Label };
42 changes: 42 additions & 0 deletions app/components/ui/radio-group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import * as React from "react";
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
import { Circle } from "lucide-react";

import { cn } from "~/lib/utils";

const RadioGroup = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
>(({ className, ...props }, ref) => {
return (
<RadioGroupPrimitive.Root
className={cn("grid gap-2", className)}
{...props}
ref={ref}
/>
);
});
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;

const RadioGroupItem = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
>(({ className, ...props }, ref) => {
return (
<RadioGroupPrimitive.Item
ref={ref}
className={cn(
"aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
>
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
<Circle className="h-2.5 w-2.5 fill-current text-current" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
);
});
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;

export { RadioGroup, RadioGroupItem };
28 changes: 28 additions & 0 deletions app/firebase/subscription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
collection,
type DocumentData,
onSnapshot,
query,
} from "firebase/firestore";
import { type SWRSubscription } from "swr/subscription";
import { db } from "./firestore";

// データの型はあとでマシなものにする
export const collectionSub: SWRSubscription<string, DocumentData[], Error> = (
key,
{ next },
) => {
const unsub = onSnapshot(
query(collection(db, key)),
(snapshot) => {
next(
null,
snapshot.docs.map((doc) => doc.data()),
);
},
(err) => {
next(err);
},
);
return unsub;
};
78 changes: 78 additions & 0 deletions app/routes/items.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type { ActionFunction, MetaFunction } from "@remix-run/node";
import { Form } from "@remix-run/react";
import { addDoc, collection } from "firebase/firestore";
import useSWRSubscription from "swr/subscription";
import { Button } from "~/components/ui/button";
import { Input } from "~/components/ui/input";
import { Label } from "~/components/ui/label";
import { RadioGroup, RadioGroupItem } from "~/components/ui/radio-group";
import { db } from "~/firebase/firestore";
import { collectionSub } from "~/firebase/subscription";

export const meta: MetaFunction = () => {
return [{ title: "アイテム" }];
};

export default function Item() {
const { data: items } = useSWRSubscription("items", collectionSub);

return (
<div className="font-sans p-4">
<h1 className="text-3xl">アイテム</h1>
<ul>
{items?.map((item) => (
<li key={item.id}>
<h2>{item.name}</h2>
<p>{item.price}</p>
<p>{item.type}</p>
</li>
))}
</ul>
<Form method="post">
<Input type="text" name="name" placeholder="名前" />
<Input type="number" name="price" placeholder="価格" />
<RadioGroup name="type">
<div className="flex items-center space-x-2">
<RadioGroupItem value="hot" id="hot" />
<Label htmlFor="hot">ホット</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="ice" id="ice" />
<Label htmlFor="ice">アイス</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="ore" id="ore" />
<Label htmlFor="ore">オレ</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="milk" id="milk" />
<Label htmlFor="milk">ミルク</Label>
</div>
</RadioGroup>
<Button type="submit">登録</Button>
</Form>
</div>
);
}

export const clientAction: ActionFunction = async ({ request }) => {
const formData = await request.formData();
const name = formData.get("name");
const price = formData.get("price");
const type = formData.get("type");

// あとでマシなバリデーションにする e.g. zod, conform
if (!(name && price && type)) {
return new Response("Bad Request", { status: 400 });
}

// あとでマシなエラーハンドリングにする & 処理を別ファイルに切り分ける
const docRef = await addDoc(collection(db, "items"), {
name,
price: Number(price),
type,
});

console.log("Document written with ID: ", docRef.id);
return new Response(null, { status: 204 });
};
Binary file modified bun.lockb
Binary file not shown.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"typecheck": "tsc"
},
"dependencies": {
"@fontsource-variable/noto-sans-jp": "^5.0.19",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-radio-group": "^1.2.0",
"@radix-ui/react-slot": "^1.1.0",
"@remix-run/node": "^2.11.0",
"@remix-run/react": "^2.11.0",
Expand All @@ -22,6 +23,7 @@
"lucide-react": "^0.424.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"swr": "^2.2.5",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7"
},
Expand Down

0 comments on commit df3dcd7

Please sign in to comment.