Skip to content

Commit

Permalink
Merge branch 'main' of github.com:mst-mkt/chefcam
Browse files Browse the repository at this point in the history
  • Loading branch information
mst-mkt committed Oct 27, 2024
2 parents 3a1f824 + 0e6fdc9 commit 2e3c01c
Show file tree
Hide file tree
Showing 21 changed files with 1,031 additions and 729 deletions.
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@jsr:registry=https://npm.jsr.io
2 changes: 1 addition & 1 deletion apps/backend/biome.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"extends": ["./node_modules/biome-config/base.json"],
"extends": ["./node_modules/@mst-mkt/js-config/packages/biome/config.json"],
"files": {
"ignore": ["./src/drizzle/migrations/"]
}
Expand Down
16 changes: 8 additions & 8 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,24 @@
"dependencies": {
"@ai-sdk/openai": "^0.0.55",
"@auth/core": "^0.34.2",
"@auth/drizzle-adapter": "^1.4.2",
"@auth/drizzle-adapter": "^1.5.2",
"@hono/auth-js": "^1.0.10",
"@hono/zod-validator": "^0.2.2",
"ai": "^3.3.26",
"ai": "^3.4.4",
"cheerio": "1.0.0-rc.12",
"drizzle-orm": "^0.33.0",
"hono": "^4.5.11",
"hono": "^4.6.3",
"zod": "^3.23.8"
},
"devDependencies": {
"@biomejs/biome": "^1.8.3",
"@cloudflare/workers-types": "^4.20240821.1",
"@biomejs/biome": "^1.9.2",
"@cloudflare/workers-types": "^4.20240925.0",
"@libsql/client": "^0.11.0",
"biome-config": "workspace:*",
"@mst-mkt/js-config": "npm:@jsr/mst-mkt__js-config@^0.0.1",
"dotenv": "^16.4.5",
"drizzle-kit": "^0.24.2",
"typescript": "^5.5.4",
"wrangler": "^3.74.0"
"typescript": "^5.6.2",
"wrangler": "^3.78.10"
},
"type": "module"
}
1 change: 0 additions & 1 deletion apps/backend/src/features/recipes/info/scraper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ export const scrapeRecipePage = async (html: string) => {

if (!validated.success) {
console.error('Invalid recipe:', validated.error.issues)
console.table(validated.error.issues)
return null
}

Expand Down
1 change: 0 additions & 1 deletion apps/backend/src/features/recipes/scraper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ const scrapeCookpadHtml = async (html: string) => {
const validatedRecipe = recipeSchema.safeParse(newRecipe)
if (!validatedRecipe.success) {
console.error('Invalid recipe:', validatedRecipe.error.issues)
console.table(validatedRecipe.error.issues)
return null
}
return validatedRecipe.data
Expand Down
2 changes: 2 additions & 0 deletions apps/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ const routes = app
.route('/favorite', favoriteRouter)

export type HonoRoutes = typeof routes

// biome-ignore lint/style/noDefaultExport: this file is the entry point of the app
export default app
5 changes: 4 additions & 1 deletion apps/backend/wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ database_id = "efd66620-172b-4305-a21a-e1d6e5a881da"
migrations_dir = "src/drizzle/migrations"

# [ai]
# binding = "AI"
# binding = "AI"

[observability]
enabled = true
4 changes: 2 additions & 2 deletions apps/frontend/biome.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"extends": ["./node_modules/biome-config/base.json"],
"extends": ["./node_modules/@mst-mkt/js-config/packages/biome/config.json"],
"files": {
"ignore": ["./src/styles/index.css"]
"ignore": ["./src/styles/index.css", "./src/lib/tanstack-router/route-tree.gen.ts"]
}
}
26 changes: 13 additions & 13 deletions apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,32 @@
},
"dependencies": {
"@hono/auth-js": "^1.0.10",
"@tabler/icons-react": "^3.14.0",
"@tanstack/react-router": "^1.52.5",
"@tanstack/router-devtools": "^1.52.5",
"hono": "^4.5.11",
"@tabler/icons-react": "^3.17.0",
"@tanstack/react-router": "^1.58.11",
"@tanstack/router-devtools": "^1.58.11",
"hono": "^4.6.3",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-webcam": "^7.2.0",
"tailwind-merge": "^2.5.2",
"zod": "^3.23.8"
},
"devDependencies": {
"@biomejs/biome": "^1.8.3",
"@biomejs/biome": "^1.9.2",
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tanstack/router-vite-plugin": "^1.52.0",
"@types/react": "^18.3.5",
"@tanstack/router-vite-plugin": "^1.58.10",
"@types/react": "^18.3.9",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react-swc": "^3.7.0",
"autoprefixer": "^10.4.20",
"backend": "workspace:*",
"biome-config": "workspace:*",
"postcss": "^8.4.44",
"@mst-mkt/js-config": "npm:@jsr/mst-mkt__js-config@^0.0.1",
"postcss": "^8.4.47",
"postcss-import": "^16.1.0",
"tailwind-scrollbar": "^3.1.0",
"tailwindcss": "^3.4.10",
"typescript": "^5.5.4",
"vite": "^5.4.3",
"vite-plugin-pwa": "^0.20.3"
"tailwindcss": "^3.4.13",
"typescript": "^5.6.2",
"vite": "^5.4.8",
"vite-plugin-pwa": "^0.20.5"
}
}
4 changes: 1 addition & 3 deletions apps/frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ authConfigManager.setConfig({
credentials: 'include',
})

const App = () => {
export const App = () => {
return (
<SessionProvider>
<RouterProvider router={router} />
</SessionProvider>
)
}

export default App
4 changes: 3 additions & 1 deletion apps/frontend/src/components/common/FileInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const FileInput: FC<FileInputProps> = ({ onChange, isLoading = false }) =

return (
<label
htmlFor="file-input"
className="flex aspect-2 w-full cursor-pointer flex-col items-center justify-center gap-y-2 rounded-2xl border-4 border-accent border-dotted px-16 py-8 transition-colors focus-within:bg-accent/20 hover:bg-accent/10 md:p-16"
onDrop={handleDrop}
onDragOver={handleDragOver}
Expand All @@ -43,10 +44,11 @@ export const FileInput: FC<FileInputProps> = ({ onChange, isLoading = false }) =
<IconPhotoPlus className="h-12 w-12 text-accent md:h-16 md:w-16" />
<input
type="file"
id="file-input"
className="h-0 border-0 opacity-0"
onChange={handleFileChange}
accept="image/*"
multiple
multiple={true}
/>
<p className="whitespace-pre-wrap break-keep text-center">
ファイルをドロップするか
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import ReactDom from 'react-dom/client'
import App from './App.tsx'
import { App } from './App.tsx'
import './styles/index.css'

// biome-ignore lint/style/noNonNullAssertion: #root is exist in index.html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const SkeltonRecipe: FC<SkeltonRecipeProps> = ({ search }) => (
<div className="h-[1lh] w-full animate-pulse rounded bg-foreground/30" />
</div>
<div className="line-clamp-4">
{[...Array(2)].map((_, i) => (
{[...new Array(2)].map((_, i) => (
<div
// biome-ignore lint/suspicious/noArrayIndexKey: This is a skeleton component, so index key is not a problem
key={i}
Expand All @@ -38,7 +38,7 @@ export const SkeltonRecipe: FC<SkeltonRecipeProps> = ({ search }) => (
</div>
</div>
<ul className="flex flex-col gap-y-2 rounded-md bg-background-50 p-4 text-sm">
{[...Array(5)].map((_, i) => (
{[...new Array(5)].map((_, i) => (
<li
// biome-ignore lint/suspicious/noArrayIndexKey: This is a skeleton component, so index key is not a problem
key={i}
Expand All @@ -50,7 +50,7 @@ export const SkeltonRecipe: FC<SkeltonRecipeProps> = ({ search }) => (
))}
</ul>
<ol className="flex flex-col gap-y-8">
{[...Array(8)].map((_, i) => (
{[...new Array(8)].map((_, i) => (
// biome-ignore lint/suspicious/noArrayIndexKey: This is a skeleton component, so index key is not a problem
<li key={i} className="flex gap-x-4">
<div className="sticky top-[90px] flex aspect-1 h-[1lh] items-center justify-center rounded-full bg-accent font-bold text-white">
Expand Down
1 change: 1 addition & 0 deletions apps/frontend/src/routes/_app/recipe/$recipeId/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const RecipeInfo = () => {
</div>
<div className="flex flex-col gap-y-2">
<p>{step.step}</p>
{/* biome-ignore lint/style/useExplicitLengthCheck: type of `step.images?.length` is `number | undefined` */}
{step.images?.length !== 0 && (
<div
className={twJoin(
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/routes/_app/recipe/.skelton-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const SkeltonCard: FC = () => (
<div className="h-[1lh] w-full animate-pulse rounded bg-foreground/30" />
</div>
<div className="line-clamp-2">
{[...Array(Math.floor(Math.random() * 3 + 4))].map((_, i) => (
{[...new Array(Math.floor(Math.random() * 3 + 4))].map((_, i) => (
<div
// biome-ignore lint/suspicious/noArrayIndexKey: This is a skeleton component, so index key is not a problem
key={i}
Expand Down
4 changes: 2 additions & 2 deletions apps/frontend/src/routes/_app/recipe/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const Route = createFileRoute('/_app/recipe/')({
loader: async ({ deps: { foods } }) => {
const res = await apiClient.recipes.$get({ query: { ingredients: foods } })
const data = await res.json()
if (!res.ok) throw new Error()
if (!res.ok) throw new Error(`Error: failed to fetch recipe-search data (${res.url})`)

const images = data.data.map((recipe) => recipe.image)
await preloadImages(images)
Expand Down Expand Up @@ -118,7 +118,7 @@ const PendingRecipe = () => {
</hgroup>
<SearchFoods foods={foods} handleRemoveFoodParam={handleRemoveFoodParam} />
<div className="flex flex-col gap-y-8">
{[...Array(5)].map((_, i) => (
{[...new Array(5)].map((_, i) => (
// biome-ignore lint/suspicious/noArrayIndexKey: This is a skeleton component, so index key is not a problem
<SkeltonCard key={i} />
))}
Expand Down
40 changes: 31 additions & 9 deletions apps/frontend/src/routes/_app/upload/.image-picker.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IconX } from '@tabler/icons-react'
import { IconAlertCircle, IconX } from '@tabler/icons-react'
import { type Dispatch, type FC, type SetStateAction, useMemo, useState } from 'react'
import { FileInput } from '../../../components/common/FileInput'
import { apiClient } from '../../../lib/apiClient'
Expand All @@ -17,36 +17,52 @@ export const ImagePicker: FC<ImagePickerProps> = ({
setSelectedFoods,
}) => {
const [isLoading, setIsLoading] = useState(false)

const fileUrls = useMemo(
() => foodImages.map((image) => URL.createObjectURL(image.file)),
[foodImages],
)

const noFoodsError = useMemo(() => {
const lastImage = foodImages[foodImages.length - 1]
return foodImages.length > 0 && lastImage && lastImage.foods.length === 0
}, [foodImages])

const uploadFiles = async (files: File[]) => {
setIsLoading(true)
const postImage = (file: File) => apiClient.upload.$post({ form: { file } })
const newFoodImages = await processNewFiles(files, foodImages)
updateImagesAndFoods(newFoodImages, setFoodImages, setSelectedFoods)
setIsLoading(false)
}

const processNewFiles = async (files: File[], foodImages: FoodImage[]): Promise<FoodImage[]> => {
const postImage = (file: File) => apiClient.upload.$post({ form: { file } })
const currentFiles = foodImages.map((image) => image.file)
const newFiles = files.filter((file) => !currentFiles.includes(file))

const newFoodImages = await Promise.all(
const results = await Promise.all(
newFiles.map(async (file) => {
const res = await postImage(file)

const data = await res.json()
return {
file,
foods: 'foods' in data ? data.foods : [],
}

return { file, foods: 'foods' in data ? data.foods : [] }
}),
)

return results
}

const updateImagesAndFoods = (
newFoodImages: FoodImage[],
setFoodImages: Dispatch<SetStateAction<FoodImage[]>>,
setSelectedFoods: Dispatch<SetStateAction<string[]>>,
) => {
setFoodImages((prev) => [...prev, ...newFoodImages])
setSelectedFoods((prev) => [
...prev,
...newFoodImages.flatMap((image) => image.foods).filter((food) => !prev.includes(food)),
])

setIsLoading(false)
}

const handleFileRemove = (index: number) => {
Expand All @@ -56,6 +72,12 @@ export const ImagePicker: FC<ImagePickerProps> = ({
return (
<div className="flex flex-col gap-y-4">
<FileInput onChange={uploadFiles} isLoading={isLoading} />
{noFoodsError && (
<div className="flex gap-x-2">
<IconAlertCircle size={25} className="text-red-400" />
<p>画像から食材が見つかりませんでした</p>
</div>
)}
<div className="scrollbar-thin scrollbar-thumb-rounded-full scrollbar-track-rounded-full scrollbar-thumb-gray-300 scrollbar-track-transparent flex gap-x-2 overflow-x-scroll rounded-md">
{fileUrls.map((url, i) => (
<div
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/routes/_app/upload/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const Upload = () => {
<p>5個以上の食材を選択するとレシピに含まれない食材がある場合があります</p>
</div>
)}
{foods.length !== 0 && (
{foods.length > 0 && (
<LinkButton to="/recipe" search={{ foods: selectedFoods }}>
レシピを検索
</LinkButton>
Expand Down
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"extends": ["./node_modules/biome-config/base.json"]
"extends": ["./node_modules/@mst-mkt/js-config/packages/biome/config.json"]
}
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
"prepare": "husky"
},
"devDependencies": {
"@biomejs/biome": "^1.8.3",
"biome-config": "workspace:*",
"husky": "^9.1.5",
"@biomejs/biome": "^1.9.2",
"@mst-mkt/js-config": "npm:@jsr/mst-mkt__js-config@^0.0.1",
"husky": "^9.1.6",
"lint-staged": "^15.2.10",
"turbo": "^2.1.1"
"turbo": "^2.1.2"
},
"lint-staged": {
"*.{js,ts,jsx,tsx,css}": [
Expand Down
Loading

0 comments on commit 2e3c01c

Please sign in to comment.