Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit cf26f4b
Author: nasubi916 <[email protected]>
Date:   Fri Nov 8 00:34:02 2024 +0900

    スポンサーログイン

commit 9af88a5
Author: nasubi916 <[email protected]>
Date:   Fri Nov 8 00:08:06 2024 +0900

    年齢入力

commit 7bba08c
Author: nasubi916 <[email protected]>
Date:   Thu Nov 7 23:04:23 2024 +0900

    仮アカウントログインからgoogleに変更

commit dd23d39
Author: nasubi916 <[email protected]>
Date:   Tue Nov 5 23:05:48 2024 +0900

    💄 ユーザー認証画面にアカウントタイプ選択ボタンを追加
  • Loading branch information
nasubi-dev committed Nov 7, 2024
1 parent 0475d03 commit 2c2901c
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 15 deletions.
61 changes: 61 additions & 0 deletions src/components/sva/inputNumber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { numberInputAnatomy } from "@ark-ui/react";
import { sva } from "panda/css";

/**
* Ark UI の [Popover コンポーネント](https://ark-ui.com/react/docs/components/popover) の基底スタイル
*
* 書き方 refs:
* - https://panda-css.com/docs/concepts/slot-recipes
* - https://ark-ui.com/react/docs/guides/styling#styling-with-panda-css
* - https://speakerdeck.com/ikumatadokoro/panda-css-to-ark-ui-dehazimeruge-ren-kai-fa?slide=31
*/
export const svaNumberInput = sva({
className: "NumberInput",
slots: numberInputAnatomy.keys(),
base: {
root: {
width: "100%",
margin: "auto",
borderRadius: "md",
padding: "1rem",
border: "1px solid",
borderColor: "wkb-neutral.900",
position: "relative",
},
label: {
fontSize: "sm",
fontWeight: "bold",
position: "absolute",
top: "-1.5rem",
},
input: {
color: "wkb-neutral.900",
rounded: "md",
shadow: "md",
width: "100%",
p: "1rem",
textAlign: "left",
},
incrementTrigger: {
bg: "wkb-neutral.900",
rounded: "md",
shadow: "md",
},
decrementTrigger: {
bg: "wkb-neutral.900",
rounded: "md",
shadow: "md",
},
control: {
display: "flex",
flexDirection: "column",
position: "absolute",
right: "0",
top: "0",
bottom: "0",
justifyContent: "space-between",
bg: "wkb-neutral.100",
color: "wkb-neutral.900",
},
},
});
8 changes: 5 additions & 3 deletions src/lib/classes/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ export class User {

static async signIn(): Promise<void> {
match(
await supabase.auth.signInWithPassword({
email: "[email protected]",
password: "password",
await supabase.auth.signInWithOAuth({
provider: "google",
options: {
redirectTo: `${document.location.origin}/user/auth`,
},
}),
).with(S.Error, ({ error }) => {
notifyErrorInToast("User.signIn", error, "サインインに失敗しました");
Expand Down
185 changes: 173 additions & 12 deletions src/routes/user/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { Field, NumberInput } from "@ark-ui/react";
import { Icon } from "@iconify/react";
import { type Session } from "@supabase/supabase-js";
import { createFileRoute } from "@tanstack/react-router";
import { useSetAtom } from "jotai";
import { styled as p, VStack } from "panda/jsx";
import { type ReactElement } from "react";
import { Grid, styled as p, VStack } from "panda/jsx";
import { useState, type ReactElement } from "react";
import { z } from "zod";
import { IconText } from "@/components/IconText";
import { Button } from "@/components/cva/Button";
import { Expanded } from "@/components/cva/Expanded";
import { useSession } from "@/hooks/useSession";
import { svaNumberInput } from "@/components/sva/numberInput";
import { svaTextArea } from "@/components/sva/textArea";
import { User } from "@/lib/classes/user";
import { $redirectTo } from "@/lib/stores/redirect";
import { notifyTableErrorInToast } from "@/lib/utils/table";

export const Route = createFileRoute("/user/")({
validateSearch: (s) =>
Expand All @@ -20,24 +22,183 @@ export const Route = createFileRoute("/user/")({
})
.parse(s),
component: () => {
const { session } = useSession();
const { session } = Route.useRouteContext();

if (session == null) return <NotAuthenticated />;
const user = new User(session);

return session != null ? (
<Authenticated session={session} />
<Authenticated user={user} />
) : (
<NotAuthenticated />
);
},
});

function Authenticated({ session }: { session: Session }): ReactElement {
const { metadata } = new User(session);
function Authenticated({ user }: { user: User }): ReactElement {
const [selected, setSelected] = useState<"sower" | "sponsor" | null>();
const [age, setAge] = useState(0);
const [description, setDescription] = useState("");
const numberInput = svaNumberInput();
const textArea = svaTextArea();

return (
<Expanded items="center">
<VStack>
<p.p>ログインしました!</p.p>
<p.p>{metadata.name}</p.p>
<VStack gap="10" p="10">
{selected == null && (
<>
<p.span fontSize="xl" fontWeight="bold">
アカウントタイプを選択して下さい
</p.span>
<Grid
gap="4"
gridTemplate={{ base: "1fr", md: "1fr / repeat(2, 1fr)" }}
>
<Button
h="300px"
onClick={() => {
setSelected("sower");
}}
variant="outlined"
w="300px"
>
<VStack gap="2">
<IconText
icon="bi:person-circle"
iconProps={{ height: "3em" }}
>
<p.p fontSize="lg" fontWeight="bold">
市民としてログイン
</p.p>
</IconText>
<p.p fontSize="xs">
スマートシティーに住む住人として意見を発言、プロジェクトの支援のためにこのサービスを使う
</p.p>
</VStack>
</Button>
<Button
h="300px"
onClick={() => {
setSelected("sponsor");
}}
variant="outlined"
w="300px"
>
<VStack gap="2">
<IconText icon="bi:building" iconProps={{ height: "3em" }}>
<p.p fontSize="lg" fontWeight="bold">
企業としてログイン
</p.p>
</IconText>
<p.p fontSize="xs">
スマートシティーに企業として参入するためにこのサービスを使う
</p.p>
</VStack>
</Button>
</Grid>
</>
)}
{selected === "sower" && (
<>
<p.span>年齢を入力して下さい</p.span>
<p.div h="100px" w="300px">
<NumberInput.Root
allowMouseWheel
className={numberInput.root}
max={200}
min={0}
>
<NumberInput.Input
className={numberInput.input}
onChange={(e) => {
setAge(Number(e.target.value));
}}
/>
<NumberInput.Control className={numberInput.control}>
<NumberInput.IncrementTrigger
className={numberInput.decrementTrigger}
onClick={() => {
setAge((prev) => prev + 1);
}}
>
<Icon
icon="material-symbols:keyboard-arrow-up-rounded"
width="30px"
/>
</NumberInput.IncrementTrigger>
<NumberInput.DecrementTrigger
className={numberInput.incrementTrigger}
onClick={() => {
setAge((prev) => prev - 1);
}}
>
<Icon
icon="material-symbols:keyboard-arrow-down-rounded"
width="30px"
/>
</NumberInput.DecrementTrigger>
</NumberInput.Control>
</NumberInput.Root>
</p.div>
<Button
h="100px"
onClick={() => {
void user
.registerAsASower({
user_id: user.id,
name: user.metadata.name ?? "名無し",
birthday: `${new Date().getFullYear() - age}-10-05T14:48:00.000Z`,
})
.mapErr(notifyTableErrorInToast("User.registerAsASower"));
}}
variant="outlined"
w="300px"
>
<VStack gap="2">
<IconText icon="bi:person-circle" iconProps={{ height: "3em" }}>
<p.p fontSize="lg" fontWeight="bold">
市民としてログイン
</p.p>
</IconText>
</VStack>
</Button>
</>
)}
{selected === "sponsor" && (
<>
<p.span>企業の説明を入力して下さい</p.span>
<Field.Root className={textArea.root}>
<Field.Textarea
className={textArea.textarea}
onChange={(e) => {
setDescription(e.target.value);
}}
value={description}
/>
</Field.Root>
<Button
h="100px"
onClick={() => {
void user.registerAsASponsor({
user_id: user.id,
name: user.metadata.name,
icon: user.metadata.picture,
description,
});
}}
variant="outlined"
w="300px"
>
<VStack gap="2">
<IconText icon="bi:building" iconProps={{ height: "3em" }}>
<p.p fontSize="lg" fontWeight="bold">
企業としてログイン
</p.p>
</IconText>
</VStack>
</Button>
</>
)}
</VStack>
</Expanded>
);
Expand All @@ -54,7 +215,7 @@ function NotAuthenticated(): ReactElement {
<p.p>まずはログインしてみましょう!</p.p>
<Button
onClick={() => {
setRedirectTo(redirectTo ?? "/");
setRedirectTo(redirectTo ?? "/user");
void User.signIn();
}}
variant="filled"
Expand Down

0 comments on commit 2c2901c

Please sign in to comment.