Skip to content
This repository has been archived by the owner on Feb 11, 2023. It is now read-only.

Commit

Permalink
Merge pull request #73 from re-taro/feat/#22
Browse files Browse the repository at this point in the history
deps: Add react-hook-form and jotai
  • Loading branch information
re-taro authored Dec 14, 2022
2 parents 3bda591 + ae0c61c commit ad0757a
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 124 deletions.
1 change: 1 addition & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ rules:
- 2
- namedComponents: arrow-function
react/jsx-props-no-spreading: off
react/require-default-props: off
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,18 @@
"@next/font": "13.0.6",
"firebase": "9.15.0",
"framer-motion": "7.8.0",
"jotai": "1.11.2",
"next": "13.0.6",
"next-pwa": "5.6.0",
"next-seo": "5.15.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "7.40.0",
"sharp": "0.31.2"
},
"devDependencies": {
"@chakra-ui/cli": "2.2.0",
"@chakra-ui/system": "2.3.4",
"@next/env": "13.0.6",
"@types/react": "18.0.26",
"@typescript-eslint/eslint-plugin": "5.46.1",
Expand Down
27 changes: 27 additions & 0 deletions src/components/form/menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { UseFormRegister } from "react-hook-form";
import type { FC, FormEventHandler } from "react";
import { Input } from "../shared/form/input";
import type { CreateStoreMenuListItem } from "../../libs/firebase/store";

type MenuFormProps = {
register: UseFormRegister<CreateStoreMenuListItem>;
handleSubmit: FormEventHandler<HTMLFormElement>;
};

export const MenuForm: FC<MenuFormProps> = ({ register, handleSubmit }) => (
<form onSubmit={handleSubmit} id="menu">
<Input
{...register("name")}
label="相手の名前"
size="lg"
placeholder="ありばむ太郎"
/>
<Input
{...register("date")}
label="記念日"
size="lg"
placeholder="○月○日"
/>
<Input {...register("title")} label="タイトル" size="lg" placeholder="" />
</form>
);
1 change: 1 addition & 0 deletions src/components/layout/header/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const MenuHeader: FC = () => {
top={0}
w="full"
py="4"
zIndex={100}
>
<Logo />
<Button
Expand Down
1 change: 1 addition & 0 deletions src/components/layout/header/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const ViewHeader: FC<ViewHeaderProps> = ({ date, name, title }) => (
position="fixed"
w="full"
py={2}
zIndex={100}
>
<Flex>
<Icon icon="mdi:cake-variant-outline" width="1.25rem" height="1.25rem" />
Expand Down
34 changes: 34 additions & 0 deletions src/components/shared/form/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { InputProps } from "@chakra-ui/react";
import { Input as ChakraInput } from "@chakra-ui/react";
import { forwardRef } from "react";
import type { WrapperProps } from "./wrapper";
import { Wrapper } from "./wrapper";

export type ControlledInputProps = WrapperProps & InputProps;

// eslint-disable-next-line react/display-name
export const Input = forwardRef<HTMLInputElement, ControlledInputProps>(
(
{ label, errorText, helperText, isInvalid, isRequired, ...inputProps },
ref,
) => (
<Wrapper
label={label}
errorText={errorText}
helperText={helperText}
isInvalid={isInvalid}
isRequired={isRequired}
>
<ChakraInput
ref={ref}
focusBorderColor="extra.500"
color="extra.500"
_placeholder={{ opacity: 0.6, color: "inherit" }}
variant="outline"
borderRadius="8px"
{...inputProps}
isRequired={isRequired}
/>
</Wrapper>
),
);
36 changes: 36 additions & 0 deletions src/components/shared/form/wrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type {
FormControlProps,
FormErrorMessageProps,
FormLabelProps,
HelpTextProps,
} from "@chakra-ui/react";
import {
FormControl,
FormErrorMessage,
FormHelperText,
FormLabel,
} from "@chakra-ui/react";
import type { ReactNode, FC } from "react";

export type WrapperProps = {
label?: FormLabelProps["children"];
errorText?: FormErrorMessageProps["children"];
helperText?: HelpTextProps["children"];
children?: ReactNode;
} & Pick<FormControlProps, "isInvalid" | "isRequired">;

export const Wrapper: FC<WrapperProps> = ({
label,
errorText,
helperText,
isInvalid,
isRequired,
children,
}) => (
<FormControl isInvalid={isInvalid} isRequired={isRequired}>
{label && <FormLabel>{label}</FormLabel>}
{children}
{errorText && <FormErrorMessage>{errorText}</FormErrorMessage>}
{helperText && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
);
114 changes: 90 additions & 24 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,95 @@
import { Box, Text } from "@chakra-ui/react";
import type { HTMLChakraProps } from "@chakra-ui/react";
import type { NextPageWithLayout } from "next";
import type { FC } from "react";
import { VStack, Box, useDisclosure } from "@chakra-ui/react";
import { SubmitHandler, useForm } from "react-hook-form";
import { useState, useEffect, Suspense } from "react";
import { MenuCard } from "../components/card/menu";
import { MenuLayout } from "../components/layout/menu";
import { IconButton } from "../components/shared/button/icon-button";
import { Modal } from "../components/shared/modal";
import { MenuForm } from "../components/form/menu";
import type {
CreateStoreMenuListItem,
StoreMenuList,
} from "../libs/firebase/store";
import { useAuthContext } from "../contexts/auth";
import { getMenuList, createMenuListItem } from "../libs/firebase/store";

const GradientText: FC<HTMLChakraProps<"p">> = (chakraProps) => (
<Text
fontSize="6vw"
background="linear-gradient(90deg, #4d62d0, #d152c9 30%, #e6b357)"
backgroundClip="text"
{...chakraProps}
/>
);
const Menu: NextPageWithLayout = () => {
const [list, setList] = useState<StoreMenuList>([]);
const [loading, setLoading] = useState<boolean>(true);
const { user } = useAuthContext();
useEffect(() => {
(async () => {
if (user) {
const res = await getMenuList(user.uid);
setList(res);
setLoading(false);
}
})();
}, [user]);
const { isOpen, onOpen, onClose } = useDisclosure();
const { register, handleSubmit, reset } = useForm<CreateStoreMenuListItem>({
defaultValues: {
name: "",
date: "",
title: "",
},
mode: "onBlur",
});
const onSubmit: SubmitHandler<CreateStoreMenuListItem> = async (result) => {
if (!user) {
return;
}
const item = await createMenuListItem(user.uid, result);
setList([...list, item]);
onClose();
reset();
};
if (loading) return <p>Loading</p>;
return (
<>
<Box as="section" w="full">
<VStack align="stretch" spacing="7">
<Suspense>
{list.map((data) => (
<MenuCard
date={data.date}
id={data.id}
name={data.name}
key={data.id}
/>
))}
</Suspense>
</VStack>
<IconButton
position="fixed"
label="plus"
icon="ic:round-add"
fontSize="2xl"
onClick={onOpen}
zIndex={100}
right={{ base: "8", lg: "23%" }}
bottom={{ base: "5", lg: "36" }}
/>
</Box>
<Modal
footer={
<IconButton
label="send"
icon="material-symbols:send"
type="submit"
form="menu"
/>
}
isOpen={isOpen}
onClose={onClose}
>
<MenuForm register={register} handleSubmit={handleSubmit(onSubmit)} />
</Modal>
</>
);
};

const Index: NextPageWithLayout = () => (
<Box
height="100vh"
display="flex"
justifyContent="center"
alignItems="center"
>
<GradientText as="h2">Hello Chakra UI</GradientText>
</Box>
);
Menu.getLayout = (page) => <MenuLayout>{page}</MenuLayout>;

Index.getLayout = (page) => <MenuLayout>{page}</MenuLayout>;

export default Index;
export default Menu;
Loading

0 comments on commit ad0757a

Please sign in to comment.