diff --git a/frontend/src/components/ui/ComposeCanvas.tsx b/frontend/src/components/ui/ComposeCanvas.tsx index 6fbe3b9..e716751 100644 --- a/frontend/src/components/ui/ComposeCanvas.tsx +++ b/frontend/src/components/ui/ComposeCanvas.tsx @@ -3,7 +3,11 @@ import { forwardRef, useEffect, useImperativeHandle, useRef } from "react"; const PAD = 36; -export const ComposeCanvas = forwardRef((_props, ref) => { +export type CanvasTools = { + addImage: (url: string) => void; +}; + +export const ComposeCanvas = forwardRef((_props, ref) => { const wrapperRef = useRef(null); const canvasRef = useRef(null); const fabricRef = useRef(null); @@ -137,6 +141,8 @@ export const ComposeCanvas = forwardRef((_props, ref) => { fabricRef.current?.add(img); fabricRef.current?.setActiveObject(img); fabricRef.current?.requestRenderAll(); + + URL.revokeObjectURL(url); // cleanup browser upload }); }, })); @@ -155,3 +161,4 @@ export const ComposeCanvas = forwardRef((_props, ref) => { ); }); +ComposeCanvas.displayName = "ComposeCanvas"; diff --git a/frontend/src/hooks/useAuth.ts b/frontend/src/hooks/useAuth.ts index 1e67da8..1515067 100644 --- a/frontend/src/hooks/useAuth.ts +++ b/frontend/src/hooks/useAuth.ts @@ -1,13 +1,7 @@ import { useCallback } from "react"; import { api, publicApi } from "../api/apiClient"; import { endpoints } from "../config/endpoints"; -import { useAuthStore } from "../store/useAuthStore"; - -interface UserProfile { - public_id: string; - email: string; - full_name: string; -} +import { type UserProfile, useAuthStore } from "../store/useAuthStore"; export const useAuth = () => { const { accessToken, user, isInitializing, setAuth, clearAuth } = @@ -15,7 +9,7 @@ export const useAuth = () => { const isAuthenticated = !!accessToken; - const login = async (access: string, profile: UserProfile) => { + const login = (access: string, profile: UserProfile) => { setAuth(access, profile); }; diff --git a/frontend/src/pages/Editor.tsx b/frontend/src/pages/Editor.tsx index 363ca15..651a5d1 100644 --- a/frontend/src/pages/Editor.tsx +++ b/frontend/src/pages/Editor.tsx @@ -1,15 +1,18 @@ import { ImageIcon, LockIcon, TrayIcon } from "@phosphor-icons/react"; import { useRef, useState } from "react"; -import { ComposeCanvas } from "../components/ui/ComposeCanvas"; +import { + type CanvasTools, + ComposeCanvas, +} from "../components/ui/ComposeCanvas"; import DateDisplay from "../components/ui/DateDisplay"; export default function Editor() { const [recipient, setRecipient] = useState(""); - const canvasRef = useRef(null); - const _fileInputRef = useRef(null); - const _handleImageUpload = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; + const canvasRef = useRef(null); + const fileInputRef = useRef(null); + const handleImageUpload = (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; // pick one file at a time if (file) { const url = URL.createObjectURL(file); canvasRef.current?.addImage(url); @@ -47,14 +50,14 @@ export default function Editor() { diff --git a/frontend/src/pages/Register.tsx b/frontend/src/pages/Register.tsx index efb1d92..c6dfaed 100644 --- a/frontend/src/pages/Register.tsx +++ b/frontend/src/pages/Register.tsx @@ -9,6 +9,7 @@ import { publicApi } from "../api/apiClient"; import Logo from "../components/Logo"; import FormField from "../components/ui/FormField"; import { endpoints } from "../config/endpoints"; +import { ROUTES } from "../config/routes"; // validation logic const registerSchema = z @@ -47,7 +48,7 @@ export default function Register() { email: data.email, password: data.password, }); - navigate("/verify-email"); + navigate(ROUTES.VERIFY_EMAIL); } catch (err) { console.error("Registration error:", err); let message = "Registration failed. Please try again."; diff --git a/frontend/src/pages/VerifyEmail.tsx b/frontend/src/pages/VerifyEmail.tsx index cc7d230..52d1557 100644 --- a/frontend/src/pages/VerifyEmail.tsx +++ b/frontend/src/pages/VerifyEmail.tsx @@ -29,13 +29,14 @@ export default function VerifyEmail() {

-

window.close()} onKeyDown={(e) => e.key === "Enter" && window.close()} > You can close this window now. -

+ ); } diff --git a/frontend/src/store/useAuthStore.ts b/frontend/src/store/useAuthStore.ts index b805a59..d9ee990 100644 --- a/frontend/src/store/useAuthStore.ts +++ b/frontend/src/store/useAuthStore.ts @@ -1,6 +1,6 @@ import { create } from "zustand"; -interface UserProfile { +export interface UserProfile { public_id: string; email: string; full_name: string; diff --git a/frontend/src/utils/crypto.ts b/frontend/src/utils/crypto.ts index bdd6b1e..dc66b80 100644 --- a/frontend/src/utils/crypto.ts +++ b/frontend/src/utils/crypto.ts @@ -66,7 +66,8 @@ export async function encryptLetter(plaintext: string, masterKey: CryptoKey) { const rawKey = await crypto.subtle.exportKey("raw", dek); // conversion to base64 for transit - const toBase64 = (buffer: Uint8Array) => btoa(String.fromCharCode(...buffer)); + const toBase64 = (buf: Uint8Array) => + btoa(buf.reduce((acc, b) => acc + String.fromCharCode(b), "")); return { // This goes to the server