Skip to content

Commit

Permalink
Merge pull request #321 from ut-code/task/#297/add-recipe
Browse files Browse the repository at this point in the history
レシピ作成機能のUIを作った
  • Loading branch information
bvv-1 authored Mar 28, 2024
2 parents 68311ce + 4bbd108 commit c36e764
Show file tree
Hide file tree
Showing 14 changed files with 71 additions and 63 deletions.
8 changes: 4 additions & 4 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Result } from "@/pages/Result"
import { Auth } from "@/pages/Auth"
import { Favorite } from "@/pages/Favorite"
import { Setting } from "@/pages/Setting"
import { NewRecipes } from "@/pages/NewRecipes"
import { NewRecipe } from "@/pages/NewRecipe"
import { NotFound } from "@/pages/NotFound"
import { supabase } from "@/pages/Auth/supabaseClient"

Expand Down Expand Up @@ -72,19 +72,19 @@ export default function App() {
<Route path="/" element={location.search !== "?ref=a2hs" ? <HowTo /> : <Navigate replace to="/questions" />} />
<Route path="/favorites" element={<Favorite />} />
<Route path="/questions" element={<Questions />} />
<Route path="/search" element={<Result />} />
<Route path="/result" element={<Result />} />
<Route path="/setting" element={<Setting />} />
<Route
path="/auth"
element={
!session ? (
<Auth inputUsername={inputUsername} setInputUsername={setInputUsername} />
) : (
<Navigate replace to="/home" />
<Navigate replace to="/questions" />
)
}
/>
<Route path="/new" element={<NewRecipes />} />
<Route path="/new" element={<NewRecipe />} />
<Route path="*" element={<NotFound />} />
</Routes>
<BottomNavigationBar />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Loading/Loading.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styles from "./Loading.module.css"
import { InfoBox } from "../InfoBox"
import { InfoBox } from "@/components/InfoBox"

export const Loading = () => {
return (
Expand Down
12 changes: 4 additions & 8 deletions frontend/src/components/TextField/TextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@ import styles from "./TextField.module.css"

interface Props {
label: string
value: string
onChange: (value: string) => void
value: string | number | string[] | undefined
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
}

export const TextField = ({ label, value, onChange }: Props) => {
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
onChange(e.target.value)
}

return (
<div className={`${styles.root} ${value !== "" ? styles.filled : ""}`}>
<div className={`${styles.root} ${value ? styles.filled : ""}`}>
<label>{label}</label>
<input type="text" value={value} onChange={handleChange} />
<input type="text" value={value} onChange={onChange} aria-label={label} />
</div>
)
}
4 changes: 2 additions & 2 deletions frontend/src/pages/Auth/Auth.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ beforeAll(() => {
describe("SignIn component", () => {
it("should handle form submission and show success alert", async () => {
const mockSetInputUsername = vi.fn()
const { getByPlaceholderText, getByText } = render(
const { getByLabelText, getByText } = render(
<MemoryRouter>
<Auth inputUsername="" setInputUsername={mockSetInputUsername} />
</MemoryRouter>
)
const emailInput = getByPlaceholderText("メールアドレスを入力してください")
const emailInput = getByLabelText("メールアドレス")
const sendButton = getByText("サインイン")

const mockSignInWithOtp = vi.fn().mockResolvedValue({ error: null })
Expand Down
13 changes: 2 additions & 11 deletions frontend/src/pages/Auth/Auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { BackButton } from "@/components/elements/button/BackButton"
import { NextButton } from "@/components/elements/button/NextButton"
import { Loading } from "@/components/Loading"
import { TextField } from "@/components/TextField"
import { Setting } from "../Setting"

import styles from "./Auth.module.css"

Expand Down Expand Up @@ -56,7 +55,7 @@ export const Auth = ({ setInputUsername }: Props) => {
if (loading) return <Loading />
return (
<div className={styles.root}>
<BackButton onClick={() => Setting} />
<BackButton onClick={() => {}} />
<div className={styles.container}>
{hasAccount ? (
<div className={styles.title}>
Expand All @@ -72,15 +71,7 @@ export const Auth = ({ setInputUsername }: Props) => {
<div className={styles.content}>
<div className={styles.form}>
<div style={{ width: "100%" }}>
<TextField label="メールアドレス" value={email} onChange={setEmail} />
<input
type="email"
placeholder="メールアドレスを入力してください"
value={email}
required={true}
onChange={(e) => setEmail(e.target.value)}
className={styles.input}
/>
<TextField label="メールアドレス" value={email} onChange={(e) => setEmail(e.target.value)} />
</div>
<NextButton
onClick={() => handleSignIn}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
import { useState, useContext } from "react"
import { useNavigate } from "react-router-dom"
import { Link } from "react-router-dom"

import { postSubmitRecipeApi, postScrapeRecipeApi } from "@/utils/apiUtils"
import { UserContext } from "@/utils/context"
import { Recipe } from "@/utils/recipes"

import styles from "./NewRecipes.module.css"
import styles from "./NewRecipe.module.css"
import { BorderButton } from "@/components/elements/button/BorderButton"
import { BackButton } from "@/components/elements/button/BackButton"
import { NextButton } from "@/components/elements/button/NextButton"
import { Loading } from "@/components/Loading"
import { InfoBox } from "@/components/InfoBox"
import { TextField } from "@/components/TextField"
import GridViewIcon from "@mui/icons-material/GridView"

import emptyImage from "@/assets/image/Howto4.png"

export const NewRecipes = () => {
type UIState = "URL" | "Detail"

export const NewRecipe = () => {
const { session } = useContext(UserContext)
const [isLoading, setIsLoading] = useState<boolean>(false)
const [uiState, setUiState] = useState<UIState>("URL")
const [title, setTitle] = useState<string>("")
const [description, setDescription] = useState<string>("")
const [totalCookingTime, setTotalCookingTime] = useState<number>(-1)
Expand All @@ -27,6 +36,7 @@ export const NewRecipes = () => {
return
}
if (!session?.access_token) return
setIsLoading(true)
const response = await fetch(postScrapeRecipeApi(), {
method: "POST",
headers: {
Expand All @@ -45,6 +55,8 @@ export const NewRecipes = () => {
setMaterialsConverted(recipe.materials.join(","))
setFoodImageUrl(recipe.foodImageUrl)
setDish(recipe.dish)
setIsLoading(false)
setUiState("Detail")
}

const handleSubmit = async () => {
Expand Down Expand Up @@ -80,6 +92,7 @@ export const NewRecipes = () => {
const navigate = useNavigate()
// 「お気に入りにいれる」にデフォルトでチェックを入れる

if (isLoading) return <Loading />
if (!session?.access_token)
return (
<div className={styles.noResult}>
Expand All @@ -93,44 +106,44 @@ export const NewRecipes = () => {
</div>
)

if (uiState === "URL")
return (
<div style={{ padding: 16 }}>
<input type="text" value={sourceUrl} onChange={(e) => setSourceUrl(e.target.value)} />
<InfoBox />
<NextButton title={"レシピを作成する"} onClick={handleScrape} disabled={false} />
</div>
)

return (
<>
<h1>レシピ投稿機能</h1>

<label htmlFor="sourceUrl">URL</label>
<input type="text" value={sourceUrl} onChange={(e) => setSourceUrl(e.target.value)} />
<button type="button" onClick={handleScrape}>
自動スクレイピング
</button>
<br />
<label htmlFor="title">タイトル</label>
<input type="text" value={title} onChange={(e) => setTitle(e.target.value)} />
<br />
<label htmlFor="description">説明</label>
<textarea value={description} onChange={(e) => setDescription(e.target.value)} />
<br />
<label htmlFor="cookingTime">調理時間</label>
<input type="number" value={totalCookingTime} onChange={(e) => setTotalCookingTime(Number(e.target.value))} />
<br />
<label htmlFor="materials">材料</label>
<input type="text" value={materialsConverted} onChange={(e) => setMaterialsConverted(e.target.value)} />
<br />
<label htmlFor="foodImageUrl">料理画像URL</label>
<input type="text" value={foodImageUrl} onChange={(e) => setFoodImageUrl(e.target.value)} />
<br />
<BackButton onClick={() => setUiState("URL")} />
<h1>作成内容</h1>
<h4>作成するレシピの内容を確認・修正してください</h4>
<div className={styles.changeButton}>
<button>
<GridViewIcon style={{ width: 18, height: 18 }} />
<h5>表示切り替え</h5>
</button>
</div>
<img src={foodImageUrl} alt="料理画像" />
<TextField label="料理画像URL" value={foodImageUrl} onChange={(e) => setFoodImageUrl(e.target.value)} />
<TextField label="料理名" value={title} onChange={(e) => setTitle(e.target.value)} />
<TextField label="説明" value={description} onChange={(e) => setDescription(e.target.value)} />
<TextField label="材料" value={materialsConverted} onChange={(e) => setMaterialsConverted(e.target.value)} />
<label htmlFor="dish">料理の種類</label>
<select value={dish} onChange={(e) => setDish(e.target.value)}>
<option value="主食">主食</option>
<option value="主菜">主菜</option>
<option value="副菜">副菜</option>
<option value="スープ">スープ</option>
</select>
<br />
<img src={foodImageUrl} alt="料理画像" />
<br />
<button onClick={handleSubmit}>投稿</button>

<Link to="/">ホームに戻る</Link>
<TextField
label="調理時間"
value={totalCookingTime}
onChange={(e) => setTotalCookingTime(Number(e.target.value))}
/>
<NextButton title={"投稿する"} onClick={handleSubmit} disabled={false} />
</>
)
}
1 change: 1 addition & 0 deletions frontend/src/pages/NewRecipe/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./NewRecipe"
1 change: 0 additions & 1 deletion frontend/src/pages/NewRecipes/index.ts

This file was deleted.

2 changes: 1 addition & 1 deletion frontend/src/pages/Questions/Questions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const Questions = () => {
<QuestionCookingTime setQuestionNumber={setQuestionNumber} answer={cookingTime} setAnswer={setCookingTime} />
)
default:
navigate("/search")
navigate("/result")
return null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const QuestionCookingTime = ({ setQuestionNumber, answer, setAnswer }: Pr
]

const onClickNextPage = () => {
navigate("/search")
navigate("/result")
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const QuestionIngredients = ({ setQuestionNumber, ingredients, setIngredi
<div style={{ padding: 16 }}>
<div style={{ display: "inline-flex", flexDirection: "column", alignItems: "flex-start", gap: 16 }}>
<Searchbox
onClickHandler={() => navigate("/search")}
onClickHandler={() => navigate("/result")}
placeholder={"例: 卵 トマト じゃがいも"}
onChange={onChangeSearchbox}
inputContent={inputContent}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/Result/Result.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export const Result = () => {
>
<h3>もう一度検索する</h3>
</button>
<button className={styles.returnHome} onClick={() => navigate("/home")}>
<button className={styles.returnHome} onClick={() => navigate("/questions")}>
<h3>ホームへ戻る</h3>
</button>
</div>
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/pages/Setting/Setting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ export const Setting = () => {
<div className={styles.title}>
<h6>アカウント設定</h6>
</div>
<Link to={"/auth"} style={{ textDecoration: "none" }}>
<div className={styles.list}>
<div className={styles.textarea}>
<h4 style={{ fontWeight: 400 }}>サインイン周りの画面</h4>
</div>
<ArrowForwardIcon className={styles.icon} />
</div>
</Link>
<Link to={"https://gist.github.com/bvv-1/d3c318f90d0720e81259e58de49adc30"} style={{ textDecoration: "none" }}>
<div className={styles.list}>
<div className={styles.textarea}>
Expand Down

0 comments on commit c36e764

Please sign in to comment.