From a72277222f9dd21565a048c9e5d3c313fac4f2b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20Akg=C3=BCl?= <s86116@bht-berlin.de> Date: Mon, 10 Jul 2023 01:53:00 +0200 Subject: [PATCH] added better type safety and some cleanup --- .../(gaming)/games/[gameid]/page.tsx | 10 ++- app/api/gweets/route.ts | 2 +- .../create-gweet/components/create-gweet.tsx | 20 ++--- components/icons.tsx | 6 +- components/nav-sidebar.tsx | 4 +- components/profile/api/update-profile.ts | 6 +- .../profile/components/edit-profile-modal.tsx | 2 +- jest.config.mjs | 14 ++-- package-lock.json | 1 + package.json | 8 +- tsconfig.json | 79 ++++++++++--------- 11 files changed, 79 insertions(+), 73 deletions(-) diff --git a/app/(content)/(gaming)/games/[gameid]/page.tsx b/app/(content)/(gaming)/games/[gameid]/page.tsx index f344c53..cfded75 100644 --- a/app/(content)/(gaming)/games/[gameid]/page.tsx +++ b/app/(content)/(gaming)/games/[gameid]/page.tsx @@ -2,6 +2,7 @@ import AddGameDropdown from "@/components/add-game-dropdown" import AddGameToFavList from "@/components/addGameToFavList" import { BackHeader } from "@/components/back-header" import { GlobalLayout } from "@/components/global-layout" +import { TryAgain } from "@/components/try-again" import { AspectRatio } from "@/components/ui/aspect-ratio" import { Button } from "@/components/ui/button" import { Card } from "@/components/ui/card" @@ -15,6 +16,9 @@ import Image from "next/image" // renders a single game detail page export default async function GameDetail({ params }: { params: { gameid: string } }) { const data: IGame[] = await getGame(parseInt(params.gameid)) + + if (!data[0]) return <TryAgain /> + // TODO put to backend const date = formatDate(data[0].first_release_date * 1000) @@ -26,7 +30,7 @@ export default async function GameDetail({ params }: { params: { gameid: string }) const companies = data[0].involved_companies.map((company) => { - if (company !== data[0].involved_companies[0]) { + if (company !== data[0]?.involved_companies[0]) { return `, ${company.company.name}` } return company.company.name @@ -45,7 +49,7 @@ export default async function GameDetail({ params }: { params: { gameid: string <div className="h-64 overflow-hidden"> <AspectRatio ratio={889 / 500}> <Image - src={data[0].screenshots[0].url} + src={data[0].screenshots[0]?.url ?? ""} alt={data[0].name} fill priority @@ -113,7 +117,7 @@ export default async function GameDetail({ params }: { params: { gameid: string <Card key={i} className="aspect-[264/374] relative block"> <Image src={screenshot.url} - alt={data[0].name} + alt={data[0]?.name ?? ""} fill priority className="object-cover rounded-lg" /> diff --git a/app/api/gweets/route.ts b/app/api/gweets/route.ts index 036b8d3..fd57494 100644 --- a/app/api/gweets/route.ts +++ b/app/api/gweets/route.ts @@ -160,7 +160,7 @@ export async function GET(request: Request) { }, }) - const nextId = gweets.length < take ? undefined : gweets[gweets.length - 1].id + const nextId = gweets.length < take ? undefined : gweets[gweets.length - 1]?.id return NextResponse.json({ gweets, nextId }, { status: 200 }) } catch (error) { diff --git a/components/create-gweet/components/create-gweet.tsx b/components/create-gweet/components/create-gweet.tsx index 491c57b..2788484 100644 --- a/components/create-gweet/components/create-gweet.tsx +++ b/components/create-gweet/components/create-gweet.tsx @@ -114,7 +114,7 @@ export const CreateGweet = ({ const err = error as z.ZodError return toast({ variant: "destructive", - description: err.issues[0].message, + description: err.issues[0]?.message, }) } @@ -133,16 +133,18 @@ export const CreateGweet = ({ const filePath = files[i] const reader = new FileReader() - reader.readAsDataURL(filePath) + if (filePath) { + reader.readAsDataURL(filePath) - reader.onload = () => { - newImages.push({ - url: reader.result, - file: filePath, - }) + reader.onload = () => { + newImages.push({ + url: reader.result, + file: filePath, + }) - if (newImages.length === files.length) { - setChosenImages([...chosenImages, ...newImages]) + if (newImages.length === files.length) { + setChosenImages([...chosenImages, ...newImages]) + } } } } diff --git a/components/icons.tsx b/components/icons.tsx index 4c26e62..e21aac5 100644 --- a/components/icons.tsx +++ b/components/icons.tsx @@ -40,13 +40,9 @@ import { type Icon as LucideIcon, } from "lucide-react" -export type IconsType = { - [key: string]: LucideIcon -} - export type Icon = LucideIcon -export const Icons: IconsType = { +export const Icons = { logo: ({ ...props }: LucideProps) => ( <svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}> <path d="M20.5603 25.7199V34C20.5603 35.1046 19.6649 36 18.5603 36H12.2803C11.1757 36 10.2803 35.1046 10.2803 34V25.7199L15.5127 20.5L20.5603 25.7199Z" fill="#16161A" /> diff --git a/components/nav-sidebar.tsx b/components/nav-sidebar.tsx index b8f579a..382419d 100644 --- a/components/nav-sidebar.tsx +++ b/components/nav-sidebar.tsx @@ -1,6 +1,6 @@ "use client" -import { Icons, IconsType } from "@/components/icons" +import { Icons } from "@/components/icons" import { buttonVariants } from "@/components/ui/button" import { cn } from "@/lib/utils" import { SidebarNavItem } from "@/types" @@ -21,7 +21,7 @@ export const Sidebar = ({ items, user }: { items: SidebarNavItem[], user: User | return ( <nav className="grid items-start gap-2"> {visibleItems.map((item, index) => { - const Icon = Icons[item.icon as keyof IconsType || "arrowRight"] + const Icon = Icons[item.icon || "arrowRight"] if (item.title === "My Profile") { item.href = `/${user?.username}` } diff --git a/components/profile/api/update-profile.ts b/components/profile/api/update-profile.ts index 3154005..7fb9c7a 100644 --- a/components/profile/api/update-profile.ts +++ b/components/profile/api/update-profile.ts @@ -15,11 +15,13 @@ export const updateProfile = async ({ let imagefileprops: { fileUrl: string; fileKey: string } = { fileUrl: '', fileKey: '' } if (profile.banner.file) { - [bannerfileprops] = await uploadFiles({ files: [profile.banner.file], endpoint: 'mediaUploader' }) + [bannerfileprops = bannerfileprops ?? { fileUrl: '', fileKey: '' }] = + await uploadFiles({ files: [profile.banner.file], endpoint: 'mediaUploader' }) } if (profile.image.file) { - [imagefileprops] = await uploadFiles({ files: [profile.image.file], endpoint: 'imageUploader' }) + [imagefileprops = imagefileprops ?? { fileUrl: '', fileKey: '' }] = + await uploadFiles({ files: [profile.image.file], endpoint: 'imageUploader' }) } const data = await fetch(`/api/users/${userId}`, { diff --git a/components/profile/components/edit-profile-modal.tsx b/components/profile/components/edit-profile-modal.tsx index d77e188..6039e78 100644 --- a/components/profile/components/edit-profile-modal.tsx +++ b/components/profile/components/edit-profile-modal.tsx @@ -127,7 +127,7 @@ export const EditProfileModal = ({ user }: { user: IUser }) => { setImageErrorMessage("") } catch (error: any) { const err = error as z.ZodError - setImageErrorMessage(err.issues[0].message) + setImageErrorMessage(err.issues[0]?.message || "Invalid image") return } diff --git a/jest.config.mjs b/jest.config.mjs index 7079cf9..4e300ff 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -1,4 +1,4 @@ -import nextJest from 'next/jest.js'; +import nextJest from 'next/jest.js' // Provide the path to your Next.js app to load next.config.js and .env files in your test environment const createJestConfig = nextJest({ dir: './' }) @@ -9,14 +9,14 @@ const clientTestConfig = { testPathIgnorePatterns: ["<rootDir>/node_modules/", "<rootDir>/__tests__/api/"], setupFilesAfterEnv: ["<rootDir>/jest.setup.js"], testEnvironment: "jest-environment-jsdom", -}; +} // Custom server config to be passed to Jest. const serverTestConfig = { displayName: "server", testMatch: ["**/__tests__/api/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)"], testEnvironment: "jest-environment-node", -}; +} // Add any custom config to be passed to Jest /** @type {import('jest').Config} */ @@ -26,8 +26,8 @@ const config = { collectCoverageFrom: [ '**/app/api/**', '!**/node_modules/**', - '!**/vendor/**', - ] -}; + '!**/.*/**', + ], +} -export default config; \ No newline at end of file +export default config \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index bb235f4..9ac6fb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "project_ss23_gameunity", "version": "0.2.0", + "hasInstallScript": true, "dependencies": { "@auth/prisma-adapter": "^1.0.0", "@hookform/resolvers": "^3.1.1", diff --git a/package.json b/package.json index eb931eb..453dfa6 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,10 @@ "build": "next build", "start": "next start", "lint": "next lint", - "preview": "prisma generate && next build && next start", + "test": "jest --coverage", + "preview": "next build && next start", "vercel-build": "prisma generate && prisma migrate deploy && next build", - "test": "jest", - "coverage": "jest --coverage" + "postinstall": "prisma generate" }, "dependencies": { "@auth/prisma-adapter": "^1.0.0", @@ -79,4 +79,4 @@ "semver": "^7.5.3", "optionator": "^0.9.3" } -} +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 88c4dba..5fc1a97 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,42 +1,43 @@ { - "compilerOptions": { - "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": [ - "./*" - ] + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noUncheckedIndexedAccess": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": [ + "./*" + ] + }, + "strictNullChecks": true }, - "strictNullChecks": true - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts" - ], - "exclude": [ - "node_modules" - ] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] } \ No newline at end of file -- GitLab