import { Box, Divider, Flex, Heading, Input, Stack } from "@chakra-ui/react";
import React, { ChangeEvent, memo, useState, VFC } from "react";
import { PrimaryButton } from "../atoms/button/PrimaryButton";
import { useAuth } from "../../hooks/useAuth";
export const Login: VFC = memo(() => {
const { login, loading } = useAuth();
const [userId, setUserId] = useState("");
const onChangeUserId = (e: ChangeEvent<HTMLInputElement>) =>
setUserId(e.target.value);
const onClickLogin = () => login(userId);
return (
<Flex align="center" justify="center" height="100vh">
<Box bg="white" w="sm" p={4} borderRadius="md" shadow="md">
<Heading as="h1" size="lg" textAlign="center">
ユーザー管理アプリ
</Heading>
<Divider my={4} />
<Stack spacing={6} py={4} px={10}>
<Input
placeholder="ユーザーID"
value={userId}
onChange={onChangeUserId}
/>
<PrimaryButton
onClick={onClickLogin}
loading={loading}
disabled={userId === ""}
>
ログイン
</PrimaryButton>
</Stack>
</Box>
</Flex>
);
});
import axios from "axios";
import { useCallback, useState } from "react";
import { User } from "../types/api/user";
import { useHistory } from "react-router-dom";
export const useAuth = () => {
const history = useHistory();
const [loading, setLoading] = useState(false);
const login = useCallback(
(id: string) => {
setLoading(true);
axios
.get<User>(`https://jsonplaceholder.typicode.com/users/${id}`)
.then((res) => {
if (res.data) {
history.push("/home");
} else {
alert("ユーザーが見つかりませんでした。");
}
})
.catch(() => alert("ログイン出来ません"))
.finally(() => setLoading(false));
},
[history]
);
return { login, loading };
};
export type User = {
id: number;
name: string;
username: string;
email: string;
address: {
street: string;
suite: string;
city: string;
zipcode: string;
geo: {
lat: string;
lng: string;
};
};
phone: string;
website: string;
company: {
name: string;
catchPhrase: string;
bs: string;
};
};
import React, { memo, ReactNode, VFC } from "react";
import { Button } from "@chakra-ui/react";
type Props = {
children: ReactNode;
disabled?: boolean;
loading?: boolean;
onClick: () => void;
};
export const PrimaryButton: VFC<Props> = memo((props) => {
const { children, disabled = false, loading = false, onClick } = props;
return (
<Button
bg="teal.400"
color="white"
_hover=
isLoading={loading}
disabled={disabled || loading}
onClick={onClick}
>
{children}
</Button>
);
});
import { useToast } from "@chakra-ui/react";
import { useCallback } from "react";
type Props = {
title: string;
status: "info" | "warning" | "success" | "error";
};
export const useMessage = () => {
const toast = useToast();
const showMessage = useCallback(
(props: Props) => {
const { title, status } = props;
toast({
title,
status,
position: "top",
duration: 2000,
isClosable: true,
});
},
[toast]
);
return { showMessage };
};
import axios from "axios";
import { useCallback, useState } from "react";
import { User } from "../types/api/user";
import { useHistory } from "react-router-dom";
import { useMessage } from "./useMessage";
export const useAuth = () => {
const history = useHistory();
const { showMessage } = useMessage();
const [loading, setLoading] = useState(false);
const login = useCallback(
(id: string) => {
setLoading(true);
axios
.get<User>(`https://jsonplaceholder.typicode.com/users/${id}`)
.then((res) => {
if (res.data) {
showMessage({ title: "ログインしました", status: "success" });
history.push("/home");
} else {
showMessage({
title: "ユーザーが見つかりませんでした",
status: "error",
});
}
})
.catch(() =>
showMessage({
title: "ログイン出来ませんでした",
status: "error",
})
)
.finally(() => setLoading(false));
},
[history, showMessage]
);
return { login, loading };
};