From c5de84c0132a932ad211569e19c22012c9a31562 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sun, 20 Jul 2025 15:15:30 +0200 Subject: [PATCH] Enhance performance and error handling in the application - Optimize release profile settings in Cargo.toml - Update Dockerfile to include additional binary - Modify compose.yml to adjust database URL for read/write mode - Improve error handling in API calls within api.ts - Refactor character properties in types.ts for clarity - Update Card component to reflect new character properties - Revise utility functions for better episode handling --- Cargo.toml | 7 ++ Dockerfile | 1 + compose.yml | 2 +- frontend/bun.lockb | Bin 99074 -> 99074 bytes frontend/src/App.tsx | 17 ++--- frontend/src/api.ts | 12 +++- frontend/src/components/card.tsx | 108 ++++++++++++++++--------------- frontend/src/types.ts | 10 +-- frontend/src/utils.ts | 13 ++-- 9 files changed, 95 insertions(+), 75 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 664d660..d62711e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,3 +24,10 @@ tower-http = { version = "0.6.6", features = ["cors", "fs", "trace"] } tracing = "0.1.41" tracing-log = "0.2.0" tracing-subscriber = { version = "0.3.19", features = ["env-filter", "fmt"] } + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 +panic = "abort" +strip = true diff --git a/Dockerfile b/Dockerfile index 7f3e93c..63628b3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,6 +20,7 @@ WORKDIR /app RUN apt-get update && apt-get install -y ca-certificates openssl sqlite3 && rm -rf /var/lib/apt/lists/* RUN mkdir -p /app/data COPY --from=backend-builder /app/target/release/rick-and-morty . +COPY --from=backend-builder /app/target/release/fetch_characters . COPY --from=backend-builder /app/migrations ./migrations COPY --from=frontend-builder /app/dist ./frontend/dist EXPOSE 8000 diff --git a/compose.yml b/compose.yml index 5eb14b1..2c94a1b 100644 --- a/compose.yml +++ b/compose.yml @@ -3,7 +3,7 @@ services: build: . container_name: rick_and_morty_app environment: - DATABASE_URL: "sqlite:///app/data/rick_and_morty.db" + DATABASE_URL: "sqlite:///app/data/rick_and_morty.db?mode=rwc" BIND_ADDR: 0.0.0.0:8000 ports: - "8000:8000" diff --git a/frontend/bun.lockb b/frontend/bun.lockb index 976b69b8e5c17e0b287cce370be3a07981860960..e6a2782e796f3527ffe302c34201772eb4e6d388 100755 GIT binary patch delta 567 zcmX}nJ1>KA6vy%Bzmx^hS|}n6NO|<3McpM>j0X4Kc+{mWX#@jliWH06qw4+|BqCk` z8Vieoow^KCYu&z+;gkH%$vG!Ei(%bjSa-UY)Q*y7EtZ@Yxo7QPog(c-lB8oC!Km$j z8*O@$0U2-#N$P_GF1Rs(K@7o;e)OPMOMDyiKG{m(18;c8GvavCN`Fk{SEL(UB8F>Z zv9E^#X-G#la<$OUY_O7va+IMS6=*~iEHFbsHEgIsE$YyOX2`Ij0V@b2ge5Fv2yQsw z#5g<{m82YLn4rRiF^s^DL2c{T7zH$1Uzq!V|?PL;+UmtzjJ-*u^#uv4<%3 zq2T}#>|hgK_%Mkn_%XqVL1ahTL`h}~_nTouE85N%ggYfw*e$XmD@rt;B0B!73u~&# iFUnGVGipF?pPN<#ewVjvIxyz{cVJ|c43J6#|6#4FzLh$n;;&9^r1 zjC76*T;d8X^tYl7sfa^7k`(v%%zQ2tdC(yr1t>%jictbRN>PS#RG<=7sD=SGsD&Gg zSb_)3=tUolFu@E9tXxRyC)h9mI|kvvkh1k7+g?b|xW@zTaD!W9@Q6%gBL~}@DcFG* zyYRt}J?!HEn^?yNR

T2sve# { if (voting || !rivals[winnerIdx] || !rivals[loserIdx]) return; setVoting(true); setVotedLeft(winnerIdx === 0); - const winnerId = getId(rivals[winnerIdx]); - const loserId = getId(rivals[loserIdx]); + const winnerId = rivals[winnerIdx]!.id; + const loserId = rivals[loserIdx]!.id; if (!winnerId || !loserId) return; await rateCharacters(winnerId, loserId); const chars = await getCharacters(); diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 4f92e31..086c423 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -2,13 +2,19 @@ import type { Character } from './types'; export const getCharacters = async (): Promise => { const res = await fetch('/characters'); + if (!res.ok) { + throw new Error('Failed to fetch characters'); + } return res.json(); }; -export const rateCharacters = async (winnerId: string, loserId: string) => { - await fetch('/rate', { +export const rateCharacters = async (winnerId: number, loserId: number) => { + const res = await fetch('/rate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ winner_id: winnerId, loser_id: loserId }), + body: JSON.stringify({ winner_id: winnerId.toString(), loser_id: loserId.toString() }), }); + if (!res.ok) { + throw new Error('Failed to rate characters'); + } }; diff --git a/frontend/src/components/card.tsx b/frontend/src/components/card.tsx index f503f4b..2afbfdf 100644 --- a/frontend/src/components/card.tsx +++ b/frontend/src/components/card.tsx @@ -1,62 +1,64 @@ -import React from 'react'; -import type { Character } from '../types'; +import React from "react"; +import type { Character } from "../types"; interface CardProps { - data: Character; - isClicked?: boolean; - skipped?: boolean; - onClick?: () => void; - isRight?: boolean; + data: Character; + isClicked?: boolean; + skipped?: boolean; + onClick?: () => void; + isRight?: boolean; } export const Card: React.FC = ({ - data, - isClicked, - skipped, - onClick, + data, + isClicked, + skipped, + onClick, }) => ( -

-
- {/* FRONT */} -
-

{data.name}

- {data.name} -

Info

-
- - - - - - - - - - - - - - - - - - - - - - - -
Species{data.species}
Gender{data.gender}
Status{data.status}
Origin{data.origin.name}
Last location{data.location.name}
-
-
- {/* BACK */} -
- {/* You can put whatever you want here, like a background or extra info */} -
+
+
+ {/* FRONT */} +
+

{data.name}

+ {data.name} +

Info

+
+ + + + + + + + + + + + + + + + + + + + + + + +
Species{data.species}
Gender{data.gender}
Status{data.status}
Origin{data.origin_name}
Last location{data.location_name}
+
+ {/* BACK */} +
+ {/* You can put whatever you want here, like a background or extra info */} +
+
); diff --git a/frontend/src/types.ts b/frontend/src/types.ts index cc39132..f15a788 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -4,17 +4,19 @@ export interface OriginOrLocation { } export interface Character { - _id: string | { $oid: string }; + id: number; rmid: number; name: string; status: string; species: string; type: string; gender: string; - origin: OriginOrLocation; - location: OriginOrLocation; + origin_name: string; + origin_url: string; + location_name: string; + location_url: string; image: string; - episode: string[]; + episode: string; // This will be a stringified JSON array! url: string; created: string; elo_rating: number; diff --git a/frontend/src/utils.ts b/frontend/src/utils.ts index 292b1d9..75b1296 100644 --- a/frontend/src/utils.ts +++ b/frontend/src/utils.ts @@ -1,9 +1,10 @@ import type { Character } from "./types"; -export function getId(character: Character | null) { - if (!character) return undefined; - const id = character._id as string | { $oid: string } | undefined; - if (typeof id === 'string') return id; - if (id && typeof id.$oid === 'string') return id.$oid; - return undefined; +export function getEpisodes(character: Character): string[] { + if (Array.isArray(character.episode)) return character.episode; + try { + return JSON.parse(character.episode); + } catch { + return []; + } } \ No newline at end of file