From 4acfe07dff31a131fccc49154d30608b109a399d Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Fri, 25 Apr 2025 23:15:09 +0300 Subject: [PATCH 01/41] Design the phonebook --- app/src/components/phonebook/AddEntry.tsx | 53 +++++++ app/src/components/phonebook/DeleteDialog.tsx | 32 +++++ app/src/components/phonebook/EditDialog.tsx | 47 +++++++ app/src/components/phonebook/EntryCard.tsx | 40 ++++++ app/src/components/ui/card.tsx | 92 ++++++++++++ app/src/components/ui/dialog.tsx | 133 ++++++++++++++++++ app/src/components/ui/input.tsx | 21 +++ app/src/components/ui/label.tsx | 22 +++ app/src/pages/phonebook/phonebookPage.tsx | 53 +++++++ app/src/services/phonebookService.ts | 17 +++ app/src/utils/jsonRpcClient.ts | 23 +++ 11 files changed, 533 insertions(+) create mode 100644 app/src/components/phonebook/AddEntry.tsx create mode 100644 app/src/components/phonebook/DeleteDialog.tsx create mode 100644 app/src/components/phonebook/EditDialog.tsx create mode 100644 app/src/components/phonebook/EntryCard.tsx create mode 100644 app/src/components/ui/card.tsx create mode 100644 app/src/components/ui/dialog.tsx create mode 100644 app/src/components/ui/input.tsx create mode 100644 app/src/components/ui/label.tsx create mode 100644 app/src/pages/phonebook/phonebookPage.tsx create mode 100644 app/src/services/phonebookService.ts create mode 100644 app/src/utils/jsonRpcClient.ts diff --git a/app/src/components/phonebook/AddEntry.tsx b/app/src/components/phonebook/AddEntry.tsx new file mode 100644 index 0000000..98ad591 --- /dev/null +++ b/app/src/components/phonebook/AddEntry.tsx @@ -0,0 +1,53 @@ +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import React, { useState } from "react"; + +export function AddEntry({ onAdd }: { onAdd: (name: string, phone: string) => void }) { + const [name, setName] = useState(""); + const [phone, setPhone] = useState(""); + + const handleAdd = () => { + onAdd(name, phone); + setName(""); + setPhone(""); + }; + + return ( + + + + + + + Add new phone + +
+
+ + setName(e.target.value)} className="col-span-3" /> +
+
+ + setPhone(e.target.value)} className="col-span-3" /> +
+
+ + + +
+
+ ) +} diff --git a/app/src/components/phonebook/DeleteDialog.tsx b/app/src/components/phonebook/DeleteDialog.tsx new file mode 100644 index 0000000..f386bff --- /dev/null +++ b/app/src/components/phonebook/DeleteDialog.tsx @@ -0,0 +1,32 @@ +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" + +export function DeleteDialog() { + return ( + + + + + + + Delete phone + + Are you sure you want to delete this entry? + + + + + + + + + ) +} diff --git a/app/src/components/phonebook/EditDialog.tsx b/app/src/components/phonebook/EditDialog.tsx new file mode 100644 index 0000000..0e81309 --- /dev/null +++ b/app/src/components/phonebook/EditDialog.tsx @@ -0,0 +1,47 @@ +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" + +export function EditDialog() { + return ( + + + + + + + Edit + + Make changes here. Click save when you're done. + + +
+
+ + +
+
+ + +
+
+ + + +
+
+ ) +} diff --git a/app/src/components/phonebook/EntryCard.tsx b/app/src/components/phonebook/EntryCard.tsx new file mode 100644 index 0000000..e270154 --- /dev/null +++ b/app/src/components/phonebook/EntryCard.tsx @@ -0,0 +1,40 @@ +import React, { useState } from "react"; +import { DeleteDialog } from "./DeleteDialog"; +import { EditDialog} from "./EditDialog"; + +type EntryCardProps = { + name: string; + phone: string; + onEdit: (name: string, phone: string) => void; + onDelete: () => void; +}; + +export function EntryCard({ name, phone, onEdit, onDelete }: EntryCardProps) { + const [isEditing, setIsEditing] = useState(false); + const [editedName, setEditedName] = useState(name); + const [editedPhone, setEditedPhone] = useState(phone); + + const handleSave = () => { + onEdit(editedName, editedPhone); + setIsEditing(false); + }; + + return ( +
+ {isEditing ? ( +
+ setEditedName(e.target.value)} /> + setEditedPhone(e.target.value)} /> + +
+ ) : ( +
+

{name}

+

{phone}

+ + +
+ )} +
+ ); +} \ No newline at end of file diff --git a/app/src/components/ui/card.tsx b/app/src/components/ui/card.tsx new file mode 100644 index 0000000..d05bbc6 --- /dev/null +++ b/app/src/components/ui/card.tsx @@ -0,0 +1,92 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Card({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardAction, + CardDescription, + CardContent, +} diff --git a/app/src/components/ui/dialog.tsx b/app/src/components/ui/dialog.tsx new file mode 100644 index 0000000..981e999 --- /dev/null +++ b/app/src/components/ui/dialog.tsx @@ -0,0 +1,133 @@ +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Dialog({ + ...props +}: React.ComponentProps) { + return +} + +function DialogTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DialogPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DialogClose({ + ...props +}: React.ComponentProps) { + return +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + {children} + + + Close + + + + ) +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +} diff --git a/app/src/components/ui/input.tsx b/app/src/components/ui/input.tsx new file mode 100644 index 0000000..03295ca --- /dev/null +++ b/app/src/components/ui/input.tsx @@ -0,0 +1,21 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Input({ className, type, ...props }: React.ComponentProps<"input">) { + return ( + + ) +} + +export { Input } diff --git a/app/src/components/ui/label.tsx b/app/src/components/ui/label.tsx new file mode 100644 index 0000000..ef7133a --- /dev/null +++ b/app/src/components/ui/label.tsx @@ -0,0 +1,22 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" + +import { cn } from "@/lib/utils" + +function Label({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Label } diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx new file mode 100644 index 0000000..7992043 --- /dev/null +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -0,0 +1,53 @@ +import React, { useEffect, useState } from "react"; +import { EntryCard } from "@/components/phonebook/EntryCard"; +import { AddEntry } from "@/components/phonebook/AddEntry"; +import { fetchEntries, addEntry, editEntry, deleteEntry } from "@/services/phonebookService"; + +export function PhonebookPage() { + const [entries, setEntries] = useState<{ id: string; name: string; phone: string }[]>([]); + + useEffect(() => { + async function loadEntries() { + const data = await fetchEntries(); + setEntries(data); + } + loadEntries(); + }, []); + + const handleAddEntry = async (name: string, phone: string) => { + const newEntry = await addEntry(name, phone); + setEntries((prev) => [...prev, newEntry]); + }; + + const handleEditEntry = async (id: string, name: string, phone: string) => { + const updatedEntry = await editEntry(id, name, phone); + setEntries((prev) => + prev.map((entry) => (entry.id === id ? updatedEntry : entry)) + ); + }; + + const handleDeleteEntry = async (id: string) => { + await deleteEntry(id); + setEntries((prev) => prev.filter((entry) => entry.id !== id)); + }; + + return ( +
+
+

My Phonebook

+ +
+
+ {entries.map((entry) => ( + handleEditEntry(entry.id, name, phone)} + onDelete={() => handleDeleteEntry(entry.id)} + /> + ))} +
+
+ ); +} \ No newline at end of file diff --git a/app/src/services/phonebookService.ts b/app/src/services/phonebookService.ts new file mode 100644 index 0000000..476a702 --- /dev/null +++ b/app/src/services/phonebookService.ts @@ -0,0 +1,17 @@ +import { jsonRpcRequest } from "@/utils/jsonRpcClient"; + +export async function addEntry(name: string, phone: string) { + return await jsonRpcRequest("add_entry", { name, phone }); +} + +export async function editEntry(id: string, name: string, phone: string) { + return await jsonRpcRequest("edit_entry", { id, name, phone }); +} + +export async function deleteEntry(id: string) { + return await jsonRpcRequest("delete_entry", { id }); +} + +export async function fetchEntries() { + return await jsonRpcRequest("get_entries", {}); +} \ No newline at end of file diff --git a/app/src/utils/jsonRpcClient.ts b/app/src/utils/jsonRpcClient.ts new file mode 100644 index 0000000..9238aef --- /dev/null +++ b/app/src/utils/jsonRpcClient.ts @@ -0,0 +1,23 @@ +import axios from "axios"; + +const axiosInstance = axios.create({ + baseURL: "http://127.0.0.1:5000/rpc", // Backend JSON-RPC endpoint + headers: { + "Content-Type": "application/json", + }, +}); + +export async function jsonRpcRequest(method: string, params: any) { + try { + const response = await axiosInstance.post("", { + jsonrpc: "2.0", + method, + params, + id: Date.now(), + }); + return response.data.result; + } catch (error: any) { + console.error("JSON-RPC Error:", error.response?.data || error.message); + throw error; + } +} \ No newline at end of file From 0b5cef1b4d9689b9df6435137ddce9b2dbfaaf03 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Sat, 26 Apr 2025 00:23:09 +0300 Subject: [PATCH 02/41] Change axios integration (hopefully working) --- app/src/App.tsx | 4 +- app/src/components/phonebook/AddEntry.tsx | 43 ++++++++++---- app/src/components/phonebook/DeleteDialog.tsx | 11 +++- app/src/components/phonebook/EditDialog.tsx | 32 +++++++++-- app/src/components/phonebook/EntryCard.tsx | 57 ++++++++++++------- app/src/pages/phonebook/phonebookPage.tsx | 17 +++--- app/src/services/phonebookService.ts | 17 ------ app/src/services/phonebookService.tsx | 17 ++++++ .../{jsonRpcClient.ts => jsonRpcClient.tsx} | 2 +- 9 files changed, 135 insertions(+), 65 deletions(-) delete mode 100644 app/src/services/phonebookService.ts create mode 100644 app/src/services/phonebookService.tsx rename app/src/utils/{jsonRpcClient.ts => jsonRpcClient.tsx} (87%) diff --git a/app/src/App.tsx b/app/src/App.tsx index a392c5e..4d17ab5 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -1,4 +1,4 @@ -import { Button } from "@/components/ui/button" +import {PhonebookPage} from "@/pages/phonebook/phonebookPage.tsx"; import useT, {AutoTranslationProvider} from "@/contexts/AutoTranslationContext.tsx"; import {StorageProvider} from "@/contexts/StorageContext.tsx"; import {ThemeProvider} from "@/contexts/ThemeContext.tsx"; @@ -11,7 +11,7 @@ function App() {
- +
diff --git a/app/src/components/phonebook/AddEntry.tsx b/app/src/components/phonebook/AddEntry.tsx index 98ad591..e23ec71 100644 --- a/app/src/components/phonebook/AddEntry.tsx +++ b/app/src/components/phonebook/AddEntry.tsx @@ -1,4 +1,4 @@ -import { Button } from "@/components/ui/button" +import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, @@ -6,19 +6,21 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog" -import { Input } from "@/components/ui/input" -import { Label } from "@/components/ui/label" -import React, { useState } from "react"; +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { useState } from "react"; -export function AddEntry({ onAdd }: { onAdd: (name: string, phone: string) => void }) { +export function AddEntry({ onAdd }: { onAdd: (name: string, phone: string, email: string) => void }) { const [name, setName] = useState(""); const [phone, setPhone] = useState(""); + const [email, setEmail] = useState(""); const handleAdd = () => { - onAdd(name, phone); + onAdd(name, phone, email); setName(""); setPhone(""); + setEmail(""); }; return ( @@ -35,13 +37,34 @@ export function AddEntry({ onAdd }: { onAdd: (name: string, phone: string) => vo - setName(e.target.value)} className="col-span-3" /> + setName(e.target.value)} + className="col-span-3" + />
- setPhone(e.target.value)} className="col-span-3" /> + setPhone(e.target.value)} + className="col-span-3" + /> +
+
+ + setEmail(e.target.value)} // Fixed the bug here + className="col-span-3" + />
@@ -49,5 +72,5 @@ export function AddEntry({ onAdd }: { onAdd: (name: string, phone: string) => vo - ) + ); } diff --git a/app/src/components/phonebook/DeleteDialog.tsx b/app/src/components/phonebook/DeleteDialog.tsx index f386bff..44b79ce 100644 --- a/app/src/components/phonebook/DeleteDialog.tsx +++ b/app/src/components/phonebook/DeleteDialog.tsx @@ -9,7 +9,12 @@ import { DialogTrigger, } from "@/components/ui/dialog" -export function DeleteDialog() { +type DeleteDialogProps = { + onConfirm: () => void; + onCancel: () => void; +}; + +export function DeleteDialog({ onConfirm, onCancel }: DeleteDialogProps) { return ( @@ -23,8 +28,8 @@ export function DeleteDialog() { - - + + diff --git a/app/src/components/phonebook/EditDialog.tsx b/app/src/components/phonebook/EditDialog.tsx index 0e81309..5e1779e 100644 --- a/app/src/components/phonebook/EditDialog.tsx +++ b/app/src/components/phonebook/EditDialog.tsx @@ -10,8 +10,25 @@ import { } from "@/components/ui/dialog" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" +import { useState } from "react"; + +type EditDialogProps = { + name: string; + phone: string; + email: string; + onSave: (name: string, phone: string, email: string) => void; + onCancel: () => void; +}; + +export function EditDialog({ name, phone, email, onSave, onCancel }: EditDialogProps) { + const [editedName, setEditedName] = useState(name); + const [editedPhone, setEditedPhone] = useState(phone); + const [editedEmail, setEditedEmail] = useState(email); + + const handleSave = () => { + onSave(editedName, editedPhone, editedEmail); + }; -export function EditDialog() { return ( @@ -29,17 +46,24 @@ export function EditDialog() { - + setEditedName(e.target.value)} className="col-span-3" />
- + setEditedPhone(e.target.value)} className="col-span-3" /> +
+
+ + setEditedEmail(e.target.value)} className="col-span-3" />
- + + diff --git a/app/src/components/phonebook/EntryCard.tsx b/app/src/components/phonebook/EntryCard.tsx index e270154..8ae41e6 100644 --- a/app/src/components/phonebook/EntryCard.tsx +++ b/app/src/components/phonebook/EntryCard.tsx @@ -1,39 +1,54 @@ -import React, { useState } from "react"; +import { useState } from "react"; import { DeleteDialog } from "./DeleteDialog"; -import { EditDialog} from "./EditDialog"; +import { EditDialog } from "./EditDialog"; type EntryCardProps = { name: string; phone: string; - onEdit: (name: string, phone: string) => void; + email: string; + onEdit: (name: string, phone: string, email: string) => void; onDelete: () => void; }; -export function EntryCard({ name, phone, onEdit, onDelete }: EntryCardProps) { +export function EntryCard({ name, phone, email, onEdit, onDelete }: EntryCardProps) { const [isEditing, setIsEditing] = useState(false); - const [editedName, setEditedName] = useState(name); - const [editedPhone, setEditedPhone] = useState(phone); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); - const handleSave = () => { - onEdit(editedName, editedPhone); + const handleEditSave = (editedName: string, editedPhone: string, editedEmail: string) => { + onEdit(editedName, editedPhone, editedEmail); setIsEditing(false); }; + const handleDeleteConfirm = () => { + onDelete(); + setShowDeleteDialog(false); + }; + return (
- {isEditing ? ( -
- setEditedName(e.target.value)} /> - setEditedPhone(e.target.value)} /> - -
- ) : ( -
-

{name}

-

{phone}

- - -
+
+

{name}

+

{phone}

+

{email}

+ + +
+ + {isEditing && ( + setIsEditing(false)} + /> + )} + + {showDeleteDialog && ( + setShowDeleteDialog(false)} + /> )}
); diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index 7992043..d6dfa7f 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -1,10 +1,12 @@ -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { EntryCard } from "@/components/phonebook/EntryCard"; import { AddEntry } from "@/components/phonebook/AddEntry"; import { fetchEntries, addEntry, editEntry, deleteEntry } from "@/services/phonebookService"; export function PhonebookPage() { - const [entries, setEntries] = useState<{ id: string; name: string; phone: string }[]>([]); + const [entries, setEntries] = useState<{ + email: any; id: string; name: string; phone: string +}[]>([]); useEffect(() => { async function loadEntries() { @@ -14,13 +16,13 @@ export function PhonebookPage() { loadEntries(); }, []); - const handleAddEntry = async (name: string, phone: string) => { - const newEntry = await addEntry(name, phone); + const handleAddEntry = async (name: string, phone: string, email: string) => { + const newEntry = await addEntry(name, phone, email); setEntries((prev) => [...prev, newEntry]); }; - const handleEditEntry = async (id: string, name: string, phone: string) => { - const updatedEntry = await editEntry(id, name, phone); + const handleEditEntry = async (id: string, name: string, phone: string, email: string) => { + const updatedEntry = await editEntry(name, phone, email); setEntries((prev) => prev.map((entry) => (entry.id === id ? updatedEntry : entry)) ); @@ -43,7 +45,8 @@ export function PhonebookPage() { key={entry.id} name={entry.name} phone={entry.phone} - onEdit={(name, phone) => handleEditEntry(entry.id, name, phone)} + email={entry.email} + onEdit={(name, phone) => handleEditEntry(entry.id, name, phone, entry.email)} onDelete={() => handleDeleteEntry(entry.id)} /> ))} diff --git a/app/src/services/phonebookService.ts b/app/src/services/phonebookService.ts deleted file mode 100644 index 476a702..0000000 --- a/app/src/services/phonebookService.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { jsonRpcRequest } from "@/utils/jsonRpcClient"; - -export async function addEntry(name: string, phone: string) { - return await jsonRpcRequest("add_entry", { name, phone }); -} - -export async function editEntry(id: string, name: string, phone: string) { - return await jsonRpcRequest("edit_entry", { id, name, phone }); -} - -export async function deleteEntry(id: string) { - return await jsonRpcRequest("delete_entry", { id }); -} - -export async function fetchEntries() { - return await jsonRpcRequest("get_entries", {}); -} \ No newline at end of file diff --git a/app/src/services/phonebookService.tsx b/app/src/services/phonebookService.tsx new file mode 100644 index 0000000..2f27ee1 --- /dev/null +++ b/app/src/services/phonebookService.tsx @@ -0,0 +1,17 @@ +import { jsonRpcRequest } from "@/utils/jsonRpcClient"; + +export async function addEntry(name: string, phone: string, email: string) { + return await jsonRpcRequest("AddContact", { name, phone, email}); +} + +export async function editEntry(name: string, phone: string, email: string) { + return await jsonRpcRequest("UpdateContact", {name, phone, email}); +} + +export async function deleteEntry(id: string) { + return await jsonRpcRequest("DeleteContact", { id }); +} + +export async function fetchEntries() { + return await jsonRpcRequest("GetByName", {name: ""}); +} \ No newline at end of file diff --git a/app/src/utils/jsonRpcClient.ts b/app/src/utils/jsonRpcClient.tsx similarity index 87% rename from app/src/utils/jsonRpcClient.ts rename to app/src/utils/jsonRpcClient.tsx index 9238aef..33d1b59 100644 --- a/app/src/utils/jsonRpcClient.ts +++ b/app/src/utils/jsonRpcClient.tsx @@ -1,7 +1,7 @@ import axios from "axios"; const axiosInstance = axios.create({ - baseURL: "http://127.0.0.1:5000/rpc", // Backend JSON-RPC endpoint + baseURL: "http://127.0.0.1:5000/rpc", headers: { "Content-Type": "application/json", }, From d0d2fc80479cc24fb039712d34c1a336fa1ec9e9 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Sat, 26 Apr 2025 00:29:58 +0300 Subject: [PATCH 03/41] Added dependencies to package.json --- app/package.json | 2 ++ app/src/App.tsx | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/package.json b/app/package.json index 2952c2e..0e67903 100644 --- a/app/package.json +++ b/app/package.json @@ -11,6 +11,8 @@ }, "dependencies": { "@radix-ui/react-slot": "^1.2.0", + "@radix-ui/react-dialog": "^1.2.0", + "@radix-ui/react-label": "^1.2.0", "@tailwindcss/vite": "^4.1.4", "axios": "^1.8.4", "class-variance-authority": "^0.7.1", diff --git a/app/src/App.tsx b/app/src/App.tsx index 4d17ab5..e76f7a0 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -4,7 +4,6 @@ import {StorageProvider} from "@/contexts/StorageContext.tsx"; import {ThemeProvider} from "@/contexts/ThemeContext.tsx"; function App() { - const { _ } = useT(); return ( From 98a8c3ecb63a2a914fdb34ff1b7fe705a550bc6f Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Sat, 26 Apr 2025 00:32:20 +0300 Subject: [PATCH 04/41] Added dependencies to package.json --- app/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/package.json b/app/package.json index 0e67903..0e42d1a 100644 --- a/app/package.json +++ b/app/package.json @@ -11,8 +11,8 @@ }, "dependencies": { "@radix-ui/react-slot": "^1.2.0", - "@radix-ui/react-dialog": "^1.2.0", - "@radix-ui/react-label": "^1.2.0", + "@radix-ui/react-dialog": "^1.1.11", + "@radix-ui/react-label": "^2.1.4", "@tailwindcss/vite": "^4.1.4", "axios": "^1.8.4", "class-variance-authority": "^0.7.1", From d4361facd9b0587e11367e8e431300a7d4a5e2fa Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Sat, 26 Apr 2025 00:33:36 +0300 Subject: [PATCH 05/41] Added new dependencies to package-lock --- app/package-lock.json | 443 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 440 insertions(+), 3 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index 9fa27dd..0be928e 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -8,6 +8,8 @@ "name": "app", "version": "0.0.0", "dependencies": { + "@radix-ui/react-dialog": "^1.1.11", + "@radix-ui/react-label": "^2.1.4", "@radix-ui/react-slot": "^1.2.0", "@tailwindcss/vite": "^4.1.4", "axios": "^1.8.4", @@ -717,6 +719,11 @@ "node": ">= 8" } }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==" + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", @@ -732,6 +739,226 @@ } } }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.11.tgz", + "integrity": "sha512-yI7S1ipkP5/+99qhSI6nthfo/tR6bL6Zgxi/+1UO6qPa6UeM6nlafWcQ65vB4rU2XjgjMfMhI3k9Y5MztA62VQ==", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.7", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.4", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.6", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-slot": "1.2.0", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.7.tgz", + "integrity": "sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw==", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", + "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.4.tgz", + "integrity": "sha512-r2annK27lIW5w9Ho5NyQgqs0MmgZSTIKXWpVCJaLC1q2kZrZkcqnmHkCHMEmv8XLvsLlurKMPT+kbKkRkm/xVA==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.4.tgz", + "integrity": "sha512-wy3dqizZnZVV4ja0FNnUhIWNwWdoldXrneEyUcVtLYDAt8ovGS4ridtMAOGgXBBIfggL4BOveVWsjXDORdGEQg==", + "dependencies": { + "@radix-ui/react-primitive": "2.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.6.tgz", + "integrity": "sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw==", + "dependencies": { + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", + "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.0.tgz", + "integrity": "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw==", + "dependencies": { + "@radix-ui/react-slot": "1.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", @@ -750,6 +977,86 @@ } } }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.40.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", @@ -1527,7 +1834,7 @@ "version": "19.1.2", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.2.tgz", "integrity": "sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.0.0" @@ -1815,6 +2122,17 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2028,6 +2346,11 @@ "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2538,6 +2861,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", @@ -3414,6 +3745,72 @@ } } }, + "node_modules/react-remove-scroll": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", + "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", @@ -3636,8 +4033,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "optional": true + "license": "0BSD" }, "node_modules/tw-animate-css": { "version": "1.2.5", @@ -3715,6 +4111,47 @@ "punycode": "^2.1.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/vite": { "version": "6.2.6", "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.6.tgz", From 497c426eadc407841d80ec0658ac5e04cf16a20f Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Sat, 26 Apr 2025 00:36:21 +0300 Subject: [PATCH 06/41] Added dependencies to package.json --- app/src/App.tsx | 2 +- app/src/index.css | 45 ++++----------------------------------------- 2 files changed, 5 insertions(+), 42 deletions(-) diff --git a/app/src/App.tsx b/app/src/App.tsx index e76f7a0..482e1f4 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -1,5 +1,5 @@ import {PhonebookPage} from "@/pages/phonebook/phonebookPage.tsx"; -import useT, {AutoTranslationProvider} from "@/contexts/AutoTranslationContext.tsx"; +import {AutoTranslationProvider} from "@/contexts/AutoTranslationContext.tsx"; import {StorageProvider} from "@/contexts/StorageContext.tsx"; import {ThemeProvider} from "@/contexts/ThemeContext.tsx"; diff --git a/app/src/index.css b/app/src/index.css index 1199c18..30393bf 100644 --- a/app/src/index.css +++ b/app/src/index.css @@ -1,45 +1,6 @@ @import "tailwindcss"; @import "tw-animate-css"; -@custom-variant dark (&:is(.dark *)); - -@theme inline { - --radius-sm: calc(var(--radius) - 4px); - --radius-md: calc(var(--radius) - 2px); - --radius-lg: var(--radius); - --radius-xl: calc(var(--radius) + 4px); - --color-background: var(--background); - --color-foreground: var(--foreground); - --color-card: var(--card); - --color-card-foreground: var(--card-foreground); - --color-popover: var(--popover); - --color-popover-foreground: var(--popover-foreground); - --color-primary: var(--primary); - --color-primary-foreground: var(--primary-foreground); - --color-secondary: var(--secondary); - --color-secondary-foreground: var(--secondary-foreground); - --color-muted: var(--muted); - --color-muted-foreground: var(--muted-foreground); - --color-accent: var(--accent); - --color-accent-foreground: var(--accent-foreground); - --color-destructive: var(--destructive); - --color-border: var(--border); - --color-input: var(--input); - --color-ring: var(--ring); - --color-chart-1: var(--chart-1); - --color-chart-2: var(--chart-2); - --color-chart-3: var(--chart-3); - --color-chart-4: var(--chart-4); - --color-chart-5: var(--chart-5); - --color-sidebar: var(--sidebar); - --color-sidebar-foreground: var(--sidebar-foreground); - --color-sidebar-primary: var(--sidebar-primary); - --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); - --color-sidebar-accent: var(--sidebar-accent); - --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); - --color-sidebar-border: var(--sidebar-border); - --color-sidebar-ring: var(--sidebar-ring); -} :root { --radius: 0.625rem; @@ -112,9 +73,11 @@ @layer base { * { - @apply border-border outline-ring/50; + border: var(--color-border); + outline: 50% solid var(--color-ring); } body { - @apply bg-background text-foreground; + background-color: var(--color-background); + color: var(--color-foreground); } } From d8cb5db2dcc08f506229328b7b3d542ca1bba8bb Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Sun, 27 Apr 2025 18:27:29 +0300 Subject: [PATCH 07/41] Change axios URL and fix the dimming screen --- app/src/index.css | 38 +++++++++++++++++++++++++++++++-- app/src/utils/jsonRpcClient.tsx | 2 +- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/app/src/index.css b/app/src/index.css index 30393bf..967f0a9 100644 --- a/app/src/index.css +++ b/app/src/index.css @@ -1,8 +1,42 @@ @import "tailwindcss"; @import "tw-animate-css"; - -:root { +@theme { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); --radius: 0.625rem; --background: oklch(1 0 0); --foreground: oklch(0.141 0.005 285.823); diff --git a/app/src/utils/jsonRpcClient.tsx b/app/src/utils/jsonRpcClient.tsx index 33d1b59..348060d 100644 --- a/app/src/utils/jsonRpcClient.tsx +++ b/app/src/utils/jsonRpcClient.tsx @@ -1,7 +1,7 @@ import axios from "axios"; const axiosInstance = axios.create({ - baseURL: "http://127.0.0.1:5000/rpc", + baseURL: "backend/rpc", headers: { "Content-Type": "application/json", }, From b1809f7a68135901f1a60fe88744048dd8ad506b Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Sun, 27 Apr 2025 18:36:52 +0300 Subject: [PATCH 08/41] Fix floating box and axios URL --- app/src/pages/phonebook/phonebookPage.tsx | 2 +- app/src/utils/jsonRpcClient.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index d6dfa7f..d4748ca 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -34,7 +34,7 @@ export function PhonebookPage() { }; return ( -
+

My Phonebook

diff --git a/app/src/utils/jsonRpcClient.tsx b/app/src/utils/jsonRpcClient.tsx index 348060d..1928393 100644 --- a/app/src/utils/jsonRpcClient.tsx +++ b/app/src/utils/jsonRpcClient.tsx @@ -1,7 +1,7 @@ import axios from "axios"; const axiosInstance = axios.create({ - baseURL: "backend/rpc", + baseURL: "https://stage.dnp-project.ru/backend/rpc", headers: { "Content-Type": "application/json", }, From 4320813ff8aa35b2f52aadd2b06e58854b85d76e Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Sun, 27 Apr 2025 18:54:30 +0300 Subject: [PATCH 09/41] Correct the axios baseURL --- app/src/utils/jsonRpcClient.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/utils/jsonRpcClient.tsx b/app/src/utils/jsonRpcClient.tsx index 1928393..7bb1942 100644 --- a/app/src/utils/jsonRpcClient.tsx +++ b/app/src/utils/jsonRpcClient.tsx @@ -1,7 +1,7 @@ import axios from "axios"; const axiosInstance = axios.create({ - baseURL: "https://stage.dnp-project.ru/backend/rpc", + baseURL: "https://stage.dnp-project.ru/rpc", headers: { "Content-Type": "application/json", }, From 7b1ef87540fc6f8dc3f8fa88922b12ca7ebac6b7 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Mon, 28 Apr 2025 22:43:19 +0300 Subject: [PATCH 10/41] Change Edit/Delete buttons --- app/src/components/phonebook/DeleteDialog.tsx | 14 ++++--- app/src/components/phonebook/EditDialog.tsx | 39 +++++++++++++------ app/src/components/phonebook/EntryCard.tsx | 17 +------- app/src/pages/phonebook/phonebookPage.tsx | 21 ++++++++-- 4 files changed, 55 insertions(+), 36 deletions(-) diff --git a/app/src/components/phonebook/DeleteDialog.tsx b/app/src/components/phonebook/DeleteDialog.tsx index 44b79ce..f377003 100644 --- a/app/src/components/phonebook/DeleteDialog.tsx +++ b/app/src/components/phonebook/DeleteDialog.tsx @@ -1,4 +1,4 @@ -import { Button } from "@/components/ui/button" +import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, @@ -7,14 +7,14 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog" + DialogClose +} from "@/components/ui/dialog"; type DeleteDialogProps = { onConfirm: () => void; - onCancel: () => void; }; -export function DeleteDialog({ onConfirm, onCancel }: DeleteDialogProps) { +export function DeleteDialog({ onConfirm }: DeleteDialogProps) { return ( @@ -28,10 +28,12 @@ export function DeleteDialog({ onConfirm, onCancel }: DeleteDialogProps) { - + + + - ) + ); } diff --git a/app/src/components/phonebook/EditDialog.tsx b/app/src/components/phonebook/EditDialog.tsx index 5e1779e..e6ea7db 100644 --- a/app/src/components/phonebook/EditDialog.tsx +++ b/app/src/components/phonebook/EditDialog.tsx @@ -1,4 +1,4 @@ -import { Button } from "@/components/ui/button" +import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, @@ -7,9 +7,10 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog" -import { Input } from "@/components/ui/input" -import { Label } from "@/components/ui/label" + DialogClose +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; import { useState } from "react"; type EditDialogProps = { @@ -17,10 +18,9 @@ type EditDialogProps = { phone: string; email: string; onSave: (name: string, phone: string, email: string) => void; - onCancel: () => void; }; -export function EditDialog({ name, phone, email, onSave, onCancel }: EditDialogProps) { +export function EditDialog({ name, phone, email, onSave }: EditDialogProps) { const [editedName, setEditedName] = useState(name); const [editedPhone, setEditedPhone] = useState(phone); const [editedEmail, setEditedEmail] = useState(email); @@ -46,26 +46,43 @@ export function EditDialog({ name, phone, email, onSave, onCancel }: EditDialogP - setEditedName(e.target.value)} className="col-span-3" /> + setEditedName(e.target.value)} + className="col-span-3" + />
- setEditedPhone(e.target.value)} className="col-span-3" /> + setEditedPhone(e.target.value)} + className="col-span-3" + />
- setEditedEmail(e.target.value)} className="col-span-3" /> + setEditedEmail(e.target.value)} + className="col-span-3" + />
- + + + - ) + ); } diff --git a/app/src/components/phonebook/EntryCard.tsx b/app/src/components/phonebook/EntryCard.tsx index 8ae41e6..d15131c 100644 --- a/app/src/components/phonebook/EntryCard.tsx +++ b/app/src/components/phonebook/EntryCard.tsx @@ -11,17 +11,12 @@ type EntryCardProps = { }; export function EntryCard({ name, phone, email, onEdit, onDelete }: EntryCardProps) { - const [isEditing, setIsEditing] = useState(false); - const [showDeleteDialog, setShowDeleteDialog] = useState(false); - const handleEditSave = (editedName: string, editedPhone: string, editedEmail: string) => { onEdit(editedName, editedPhone, editedEmail); - setIsEditing(false); }; const handleDeleteConfirm = () => { onDelete(); - setShowDeleteDialog(false); }; return ( @@ -30,26 +25,16 @@ export function EntryCard({ name, phone, email, onEdit, onDelete }: EntryCardPro

{name}

{phone}

{email}

- - -
- - {isEditing && ( setIsEditing(false)} /> - )} - - {showDeleteDialog && ( setShowDeleteDialog(false)} /> - )} +
); } \ No newline at end of file diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index d4748ca..1c92e5f 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -6,7 +6,8 @@ import { fetchEntries, addEntry, editEntry, deleteEntry } from "@/services/phone export function PhonebookPage() { const [entries, setEntries] = useState<{ email: any; id: string; name: string; phone: string -}[]>([]); + }[]>([]); + const [error, setError] = useState(null); useEffect(() => { async function loadEntries() { @@ -17,8 +18,14 @@ export function PhonebookPage() { }, []); const handleAddEntry = async (name: string, phone: string, email: string) => { - const newEntry = await addEntry(name, phone, email); - setEntries((prev) => [...prev, newEntry]); + try { + const newEntry = await addEntry(name, phone, email); + setEntries((prev) => [...prev, newEntry]); + setError(null); + } catch (error: any) { + console.error("Failed to add entry:", error.response?.data || error.message); + setError(error.response?.data?.error?.message || "An error occurred while adding the entry."); + } }; const handleEditEntry = async (id: string, name: string, phone: string, email: string) => { @@ -32,6 +39,13 @@ export function PhonebookPage() { await deleteEntry(id); setEntries((prev) => prev.filter((entry) => entry.id !== id)); }; + const handleEdit = (name: string, phone: string, email: string) => { + console.log("Edited Entry:", { name, phone, email }); + }; + + const handleDelete = () => { + console.log("Entry Deleted"); + }; return (
@@ -39,6 +53,7 @@ export function PhonebookPage() {

My Phonebook

+ {error &&
{error}
}
{entries.map((entry) => ( Date: Mon, 28 Apr 2025 22:47:30 +0300 Subject: [PATCH 11/41] Fix edit/delete button duplication --- app/src/components/phonebook/EntryCard.tsx | 1 - app/src/pages/phonebook/phonebookPage.tsx | 7 ------- 2 files changed, 8 deletions(-) diff --git a/app/src/components/phonebook/EntryCard.tsx b/app/src/components/phonebook/EntryCard.tsx index d15131c..0658104 100644 --- a/app/src/components/phonebook/EntryCard.tsx +++ b/app/src/components/phonebook/EntryCard.tsx @@ -1,4 +1,3 @@ -import { useState } from "react"; import { DeleteDialog } from "./DeleteDialog"; import { EditDialog } from "./EditDialog"; diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index 1c92e5f..c70cf6d 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -39,13 +39,6 @@ export function PhonebookPage() { await deleteEntry(id); setEntries((prev) => prev.filter((entry) => entry.id !== id)); }; - const handleEdit = (name: string, phone: string, email: string) => { - console.log("Edited Entry:", { name, phone, email }); - }; - - const handleDelete = () => { - console.log("Entry Deleted"); - }; return (
From 31ad71886edc61315ad4ad3ecd09485790d151a5 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Mon, 28 Apr 2025 22:55:23 +0300 Subject: [PATCH 12/41] Edit getAll method --- app/src/components/phonebook/EditDialog.tsx | 2 +- app/src/services/phonebookService.tsx | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/components/phonebook/EditDialog.tsx b/app/src/components/phonebook/EditDialog.tsx index e6ea7db..8d15b96 100644 --- a/app/src/components/phonebook/EditDialog.tsx +++ b/app/src/components/phonebook/EditDialog.tsx @@ -55,7 +55,7 @@ export function EditDialog({ name, phone, email, onSave }: EditDialogProps) {
Date: Tue, 29 Apr 2025 13:05:30 +0300 Subject: [PATCH 13/41] Fix loading entries on start --- app/src/pages/phonebook/phonebookPage.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index c70cf6d..4c5be02 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -12,7 +12,8 @@ export function PhonebookPage() { useEffect(() => { async function loadEntries() { const data = await fetchEntries(); - setEntries(data); + const flatData = Object.values(data).flat() as {id: string; name: string; phone: string; email: string}[]; + setEntries(flatData); } loadEntries(); }, []); From dffdb9f7983fed2967d7c674efa5f30809b4f450 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 13:19:56 +0300 Subject: [PATCH 14/41] Add debug statement for EditDialog --- app/src/components/phonebook/AddEntry.tsx | 1 + app/src/components/phonebook/EditDialog.tsx | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/components/phonebook/AddEntry.tsx b/app/src/components/phonebook/AddEntry.tsx index e23ec71..41d8f0f 100644 --- a/app/src/components/phonebook/AddEntry.tsx +++ b/app/src/components/phonebook/AddEntry.tsx @@ -52,6 +52,7 @@ export function AddEntry({ onAdd }: { onAdd: (name: string, phone: string, email id="number" value={phone} onChange={(e) => setPhone(e.target.value)} + placeholder="+XXXXXXXXXXX" className="col-span-3" />
diff --git a/app/src/components/phonebook/EditDialog.tsx b/app/src/components/phonebook/EditDialog.tsx index 8d15b96..3b97ccd 100644 --- a/app/src/components/phonebook/EditDialog.tsx +++ b/app/src/components/phonebook/EditDialog.tsx @@ -21,6 +21,7 @@ type EditDialogProps = { }; export function EditDialog({ name, phone, email, onSave }: EditDialogProps) { + console.log("EditDialog Props:", { name, phone, email }); const [editedName, setEditedName] = useState(name); const [editedPhone, setEditedPhone] = useState(phone); const [editedEmail, setEditedEmail] = useState(email); @@ -55,13 +56,13 @@ export function EditDialog({ name, phone, email, onSave }: EditDialogProps) {
setEditedPhone(e.target.value)} - className="col-span-3" + className="col-span-3" placeholder="+XXXXXXXXXXX" />
From 007496fd2ba32f59b804dc68d9fbf65290459a25 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 13:37:07 +0300 Subject: [PATCH 15/41] Fix the editDialog component Currently the EditDialog component may pass null/undefined values to the backend and cause errors. This commit attempts to fix this by passing unchanged variables instead of null values if they are encountered. --- app/src/components/phonebook/EditDialog.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/components/phonebook/EditDialog.tsx b/app/src/components/phonebook/EditDialog.tsx index 3b97ccd..a40e5e0 100644 --- a/app/src/components/phonebook/EditDialog.tsx +++ b/app/src/components/phonebook/EditDialog.tsx @@ -27,7 +27,7 @@ export function EditDialog({ name, phone, email, onSave }: EditDialogProps) { const [editedEmail, setEditedEmail] = useState(email); const handleSave = () => { - onSave(editedName, editedPhone, editedEmail); + onSave(editedName || name, editedPhone || phone, editedEmail || email); }; return ( @@ -78,7 +78,7 @@ export function EditDialog({ name, phone, email, onSave }: EditDialogProps) {
- + From 7f9099cb7d9d56a5fae1e31dfe1752ae03c36f3d Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 13:57:18 +0300 Subject: [PATCH 16/41] Add more debug statements in EditDialog --- app/src/components/phonebook/EditDialog.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/components/phonebook/EditDialog.tsx b/app/src/components/phonebook/EditDialog.tsx index a40e5e0..1d14205 100644 --- a/app/src/components/phonebook/EditDialog.tsx +++ b/app/src/components/phonebook/EditDialog.tsx @@ -32,6 +32,7 @@ export function EditDialog({ name, phone, email, onSave }: EditDialogProps) { return ( + console.log("Dialog rendered"); From 354d3247266673177e051a511cd827cb3a438f5a Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:05:11 +0300 Subject: [PATCH 17/41] Attempt fixing the edit bug --- app/src/components/phonebook/EditDialog.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/components/phonebook/EditDialog.tsx b/app/src/components/phonebook/EditDialog.tsx index 1d14205..d4db614 100644 --- a/app/src/components/phonebook/EditDialog.tsx +++ b/app/src/components/phonebook/EditDialog.tsx @@ -27,12 +27,15 @@ export function EditDialog({ name, phone, email, onSave }: EditDialogProps) { const [editedEmail, setEditedEmail] = useState(email); const handleSave = () => { - onSave(editedName || name, editedPhone || phone, editedEmail || email); + onSave( + editedName !== undefined && editedName !== null ? editedName : name, + editedPhone !== undefined && editedPhone !== null ? editedPhone : phone, + editedEmail !== undefined && editedEmail !== null ? editedEmail : email + ); }; return ( - console.log("Dialog rendered"); From 993f0d564cb4ea89317058e53bff0f5d13f9eadd Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:08:01 +0300 Subject: [PATCH 18/41] Attempt fixing the edit bug 1.1 --- app/src/components/phonebook/EditDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/components/phonebook/EditDialog.tsx b/app/src/components/phonebook/EditDialog.tsx index d4db614..dc9808d 100644 --- a/app/src/components/phonebook/EditDialog.tsx +++ b/app/src/components/phonebook/EditDialog.tsx @@ -21,12 +21,12 @@ type EditDialogProps = { }; export function EditDialog({ name, phone, email, onSave }: EditDialogProps) { - console.log("EditDialog Props:", { name, phone, email }); const [editedName, setEditedName] = useState(name); const [editedPhone, setEditedPhone] = useState(phone); const [editedEmail, setEditedEmail] = useState(email); const handleSave = () => { + console.log("EditDialog Props:", { editedName, editedPhone, editedEmail }); onSave( editedName !== undefined && editedName !== null ? editedName : name, editedPhone !== undefined && editedPhone !== null ? editedPhone : phone, From 48fe874abc73a19505afccc01976262bdff3af65 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:16:43 +0300 Subject: [PATCH 19/41] Try fixing the edit bug again --- app/src/components/phonebook/EntryCard.tsx | 1 + app/src/pages/phonebook/phonebookPage.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/components/phonebook/EntryCard.tsx b/app/src/components/phonebook/EntryCard.tsx index 0658104..a6cbccc 100644 --- a/app/src/components/phonebook/EntryCard.tsx +++ b/app/src/components/phonebook/EntryCard.tsx @@ -11,6 +11,7 @@ type EntryCardProps = { export function EntryCard({ name, phone, email, onEdit, onDelete }: EntryCardProps) { const handleEditSave = (editedName: string, editedPhone: string, editedEmail: string) => { + console.log("Edited values:", { editedName, editedPhone, editedEmail }); onEdit(editedName, editedPhone, editedEmail); }; diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index 4c5be02..cf702e4 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -55,7 +55,7 @@ export function PhonebookPage() { name={entry.name} phone={entry.phone} email={entry.email} - onEdit={(name, phone) => handleEditEntry(entry.id, name, phone, entry.email)} + onEdit={(name, phone, email) => handleEditEntry(entry.id, name, phone, email)} onDelete={() => handleDeleteEntry(entry.id)} /> ))} From 9ec7ba643e8be131ac971b2e92badc116d0130aa Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:26:36 +0300 Subject: [PATCH 20/41] Fix the edit bug --- app/src/pages/phonebook/phonebookPage.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index cf702e4..aa7ec8f 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -5,7 +5,7 @@ import { fetchEntries, addEntry, editEntry, deleteEntry } from "@/services/phone export function PhonebookPage() { const [entries, setEntries] = useState<{ - email: any; id: string; name: string; phone: string + id: string; name: string; phone: string, email: string; }[]>([]); const [error, setError] = useState(null); @@ -31,6 +31,7 @@ export function PhonebookPage() { const handleEditEntry = async (id: string, name: string, phone: string, email: string) => { const updatedEntry = await editEntry(name, phone, email); + console.log("Updated Entry:", updatedEntry); setEntries((prev) => prev.map((entry) => (entry.id === id ? updatedEntry : entry)) ); From fa7b29d78a1d841c009e9e77f8868435354afe60 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:31:08 +0300 Subject: [PATCH 21/41] Fix edit bug --- app/src/pages/phonebook/phonebookPage.tsx | 2 +- app/src/services/phonebookService.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index aa7ec8f..c36b33e 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -30,7 +30,7 @@ export function PhonebookPage() { }; const handleEditEntry = async (id: string, name: string, phone: string, email: string) => { - const updatedEntry = await editEntry(name, phone, email); + const updatedEntry = await editEntry(id, name, phone, email); console.log("Updated Entry:", updatedEntry); setEntries((prev) => prev.map((entry) => (entry.id === id ? updatedEntry : entry)) diff --git a/app/src/services/phonebookService.tsx b/app/src/services/phonebookService.tsx index 6f64128..85672a1 100644 --- a/app/src/services/phonebookService.tsx +++ b/app/src/services/phonebookService.tsx @@ -4,8 +4,8 @@ export async function addEntry(name: string, phone: string, email: string) { return await jsonRpcRequest("AddContact", { name, phone, email}); } -export async function editEntry(name: string, phone: string, email: string) { - return await jsonRpcRequest("UpdateContact", {name, phone, email}); +export async function editEntry(id: string, name: string, phone: string, email: string) { + return await jsonRpcRequest("UpdateContact", {id, name, phone, email}); } export async function deleteEntry(id: string) { From bca47e49f3110943b63c27851c8e6220c4ba4435 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:34:33 +0300 Subject: [PATCH 22/41] Delete console.log debug statements --- app/src/components/phonebook/EditDialog.tsx | 1 - app/src/components/phonebook/EntryCard.tsx | 1 - app/src/pages/phonebook/phonebookPage.tsx | 1 - 3 files changed, 3 deletions(-) diff --git a/app/src/components/phonebook/EditDialog.tsx b/app/src/components/phonebook/EditDialog.tsx index dc9808d..7750f34 100644 --- a/app/src/components/phonebook/EditDialog.tsx +++ b/app/src/components/phonebook/EditDialog.tsx @@ -26,7 +26,6 @@ export function EditDialog({ name, phone, email, onSave }: EditDialogProps) { const [editedEmail, setEditedEmail] = useState(email); const handleSave = () => { - console.log("EditDialog Props:", { editedName, editedPhone, editedEmail }); onSave( editedName !== undefined && editedName !== null ? editedName : name, editedPhone !== undefined && editedPhone !== null ? editedPhone : phone, diff --git a/app/src/components/phonebook/EntryCard.tsx b/app/src/components/phonebook/EntryCard.tsx index a6cbccc..0658104 100644 --- a/app/src/components/phonebook/EntryCard.tsx +++ b/app/src/components/phonebook/EntryCard.tsx @@ -11,7 +11,6 @@ type EntryCardProps = { export function EntryCard({ name, phone, email, onEdit, onDelete }: EntryCardProps) { const handleEditSave = (editedName: string, editedPhone: string, editedEmail: string) => { - console.log("Edited values:", { editedName, editedPhone, editedEmail }); onEdit(editedName, editedPhone, editedEmail); }; diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index c36b33e..90da823 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -31,7 +31,6 @@ export function PhonebookPage() { const handleEditEntry = async (id: string, name: string, phone: string, email: string) => { const updatedEntry = await editEntry(id, name, phone, email); - console.log("Updated Entry:", updatedEntry); setEntries((prev) => prev.map((entry) => (entry.id === id ? updatedEntry : entry)) ); From 5c87d31187702e31e0d50ffcddb993e1e5c1cb59 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 15:12:22 +0300 Subject: [PATCH 23/41] Add error handling --- .../components/phonebook/ErrorBoundary.tsx | 41 ++++++++++++ app/src/components/ui/alert.tsx | 66 +++++++++++++++++++ app/src/pages/phonebook/phonebookPage.tsx | 5 +- 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 app/src/components/phonebook/ErrorBoundary.tsx create mode 100644 app/src/components/ui/alert.tsx diff --git a/app/src/components/phonebook/ErrorBoundary.tsx b/app/src/components/phonebook/ErrorBoundary.tsx new file mode 100644 index 0000000..cc799bb --- /dev/null +++ b/app/src/components/phonebook/ErrorBoundary.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert"; + +type ErrorBoundaryProps = { + children: React.ReactNode; +}; + +type ErrorBoundaryState = { + hasError: boolean; + error: Error | null; +}; + +export class ErrorBoundary extends React.Component { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { hasError: false, error: null }; + } + + static getDerivedStateFromError(error: Error) { + return { hasError: true, error }; + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.error("Error caught by ErrorBoundary:", error, errorInfo); + } + + render() { + if (this.state.hasError) { + return ( + + Error + + {this.state.error?.message || "Something went wrong."} + + + ); + } + + return this.props.children; + } +} \ No newline at end of file diff --git a/app/src/components/ui/alert.tsx b/app/src/components/ui/alert.tsx new file mode 100644 index 0000000..1421354 --- /dev/null +++ b/app/src/components/ui/alert.tsx @@ -0,0 +1,66 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const alertVariants = cva( + "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", + { + variants: { + variant: { + default: "bg-card text-card-foreground", + destructive: + "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ) +} + +function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDescription({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Alert, AlertTitle, AlertDescription } diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index 90da823..aa1ef35 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { EntryCard } from "@/components/phonebook/EntryCard"; import { AddEntry } from "@/components/phonebook/AddEntry"; import { fetchEntries, addEntry, editEntry, deleteEntry } from "@/services/phonebookService"; +import { ErrorBoundary } from "@/components/phonebook/ErrorBoundary" export function PhonebookPage() { const [entries, setEntries] = useState<{ @@ -42,7 +43,8 @@ export function PhonebookPage() { }; return ( -
+ +

My Phonebook

@@ -61,5 +63,6 @@ export function PhonebookPage() { ))}
+
); } \ No newline at end of file From bb90463453d64f4920cdcc20783366278f8e208f Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 15:24:57 +0300 Subject: [PATCH 24/41] Change error handling protocol --- .../components/phonebook/ErrorBoundary.tsx | 41 ------------------ app/src/pages/phonebook/phonebookPage.tsx | 42 ++++++++++++++----- 2 files changed, 31 insertions(+), 52 deletions(-) delete mode 100644 app/src/components/phonebook/ErrorBoundary.tsx diff --git a/app/src/components/phonebook/ErrorBoundary.tsx b/app/src/components/phonebook/ErrorBoundary.tsx deleted file mode 100644 index cc799bb..0000000 --- a/app/src/components/phonebook/ErrorBoundary.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from "react"; -import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert"; - -type ErrorBoundaryProps = { - children: React.ReactNode; -}; - -type ErrorBoundaryState = { - hasError: boolean; - error: Error | null; -}; - -export class ErrorBoundary extends React.Component { - constructor(props: ErrorBoundaryProps) { - super(props); - this.state = { hasError: false, error: null }; - } - - static getDerivedStateFromError(error: Error) { - return { hasError: true, error }; - } - - componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { - console.error("Error caught by ErrorBoundary:", error, errorInfo); - } - - render() { - if (this.state.hasError) { - return ( - - Error - - {this.state.error?.message || "Something went wrong."} - - - ); - } - - return this.props.children; - } -} \ No newline at end of file diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index aa1ef35..014ccc5 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -1,8 +1,13 @@ import { useEffect, useState } from "react"; +import { + Alert, + AlertDescription, + AlertTitle, +} from "@/components/ui/alert" import { EntryCard } from "@/components/phonebook/EntryCard"; import { AddEntry } from "@/components/phonebook/AddEntry"; import { fetchEntries, addEntry, editEntry, deleteEntry } from "@/services/phonebookService"; -import { ErrorBoundary } from "@/components/phonebook/ErrorBoundary" +import { Terminal } from "lucide-react"; export function PhonebookPage() { const [entries, setEntries] = useState<{ @@ -20,17 +25,28 @@ export function PhonebookPage() { }, []); const handleAddEntry = async (name: string, phone: string, email: string) => { - try { - const newEntry = await addEntry(name, phone, email); + if (!name || !phone || !email) { + setError("All fields are required."); + return; + } + if (!/^\+\d{11,15}$/.test(phone)) { + setError("Phone number must be written in the format +XXXXXXXXXXX"); + return; + } + const newEntry = await addEntry(name, phone, email); setEntries((prev) => [...prev, newEntry]); setError(null); - } catch (error: any) { - console.error("Failed to add entry:", error.response?.data || error.message); - setError(error.response?.data?.error?.message || "An error occurred while adding the entry."); - } }; const handleEditEntry = async (id: string, name: string, phone: string, email: string) => { + if (!name || !phone || !email) { + setError("All fields are required."); + return; + } + if (!/^\+\d{11,15}$/.test(phone)) { + setError("Phone number must be written in the format +XXXXXXXXXXX"); + return; + } const updatedEntry = await editEntry(id, name, phone, email); setEntries((prev) => prev.map((entry) => (entry.id === id ? updatedEntry : entry)) @@ -43,13 +59,18 @@ export function PhonebookPage() { }; return ( - -
+

My Phonebook

- {error &&
{error}
} + {error && + + + Something went wrong + {error} + + }
{entries.map((entry) => (
- ); } \ No newline at end of file From 047428af2315115a21d89c1711895192443a101e Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 15:33:19 +0300 Subject: [PATCH 25/41] Change error message location and some styling --- app/src/pages/phonebook/phonebookPage.tsx | 34 +++++++++++++++-------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index 014ccc5..f1d6c6b 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -24,13 +24,20 @@ export function PhonebookPage() { loadEntries(); }, []); + const handleError = (message: string) => { + setError(message); + setTimeout(() => { + setError(null); + }, 5000); + }; + const handleAddEntry = async (name: string, phone: string, email: string) => { if (!name || !phone || !email) { - setError("All fields are required."); + handleError("All fields are required."); return; } if (!/^\+\d{11,15}$/.test(phone)) { - setError("Phone number must be written in the format +XXXXXXXXXXX"); + handleError("Phone number must be written in the format +XXXXXXXXXXX"); return; } const newEntry = await addEntry(name, phone, email); @@ -40,11 +47,11 @@ export function PhonebookPage() { const handleEditEntry = async (id: string, name: string, phone: string, email: string) => { if (!name || !phone || !email) { - setError("All fields are required."); + handleError("All fields are required."); return; } if (!/^\+\d{11,15}$/.test(phone)) { - setError("Phone number must be written in the format +XXXXXXXXXXX"); + handleError("Phone number must be written in the format +XXXXXXXXXXX"); return; } const updatedEntry = await editEntry(id, name, phone, email); @@ -59,17 +66,22 @@ export function PhonebookPage() { }; return ( -
-
+
+

My Phonebook

{error && - - - Something went wrong - {error} - +
+ + + Something went wrong + {error} + +
}
{entries.map((entry) => ( From 12b8d53ea6c0743cc32cce100062d0b765fe85fc Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 18:00:25 +0300 Subject: [PATCH 26/41] Change colors, add animated error messages --- app/src/components/phonebook/AddEntry.tsx | 2 +- app/src/pages/phonebook/phonebookPage.tsx | 113 ++++++++++++++-------- 2 files changed, 72 insertions(+), 43 deletions(-) diff --git a/app/src/components/phonebook/AddEntry.tsx b/app/src/components/phonebook/AddEntry.tsx index 41d8f0f..598e4b5 100644 --- a/app/src/components/phonebook/AddEntry.tsx +++ b/app/src/components/phonebook/AddEntry.tsx @@ -26,7 +26,7 @@ export function AddEntry({ onAdd }: { onAdd: (name: string, phone: string, email return ( - + diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index f1d6c6b..3981a32 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -3,7 +3,7 @@ import { Alert, AlertDescription, AlertTitle, -} from "@/components/ui/alert" +} from "@/components/ui/alert"; import { EntryCard } from "@/components/phonebook/EntryCard"; import { AddEntry } from "@/components/phonebook/AddEntry"; import { fetchEntries, addEntry, editEntry, deleteEntry } from "@/services/phonebookService"; @@ -11,24 +11,41 @@ import { Terminal } from "lucide-react"; export function PhonebookPage() { const [entries, setEntries] = useState<{ - id: string; name: string; phone: string, email: string; + id: string; + name: string; + phone: string; + email: string; }[]>([]); const [error, setError] = useState(null); + const [showError, setShowError] = useState(false); // New state for controlling visibility useEffect(() => { async function loadEntries() { - const data = await fetchEntries(); - const flatData = Object.values(data).flat() as {id: string; name: string; phone: string; email: string}[]; - setEntries(flatData); + try { + const data = await fetchEntries(); + const flatData = Object.values(data).flat() as { + id: string; + name: string; + phone: string; + email: string; + }[]; + setEntries(flatData); + } catch (err) { + handleError("Failed to load entries."); + } } loadEntries(); }, []); const handleError = (message: string) => { setError(message); + setShowError(true); setTimeout(() => { - setError(null); - }, 5000); + setShowError(false); + setTimeout(() => { + setError(null); + }, 500); + }, 4000); }; const handleAddEntry = async (name: string, phone: string, email: string) => { @@ -40,9 +57,12 @@ export function PhonebookPage() { handleError("Phone number must be written in the format +XXXXXXXXXXX"); return; } - const newEntry = await addEntry(name, phone, email); + try { + const newEntry = await addEntry(name, phone, email); setEntries((prev) => [...prev, newEntry]); - setError(null); + } catch (err) { + handleError("Failed to add entry."); + } }; const handleEditEntry = async (id: string, name: string, phone: string, email: string) => { @@ -54,47 +74,56 @@ export function PhonebookPage() { handleError("Phone number must be written in the format +XXXXXXXXXXX"); return; } - const updatedEntry = await editEntry(id, name, phone, email); - setEntries((prev) => - prev.map((entry) => (entry.id === id ? updatedEntry : entry)) - ); + try { + const updatedEntry = await editEntry(id, name, phone, email); + setEntries((prev) => + prev.map((entry) => (entry.id === id ? updatedEntry : entry)) + ); + } catch (err) { + handleError("Failed to edit entry."); + } }; const handleDeleteEntry = async (id: string) => { - await deleteEntry(id); - setEntries((prev) => prev.filter((entry) => entry.id !== id)); + try { + await deleteEntry(id); + setEntries((prev) => prev.filter((entry) => entry.id !== id)); + } catch (err) { + handleError("Failed to delete entry."); + } }; return ( -
-
-

My Phonebook

+
+
+

My Phonebook

- {error && -
- - - Something went wrong - {error} - -
- } -
- {entries.map((entry) => ( - handleEditEntry(entry.id, name, phone, email)} - onDelete={() => handleDeleteEntry(entry.id)} - /> - ))} -
+ {error && ( +
+ + + Something went wrong + {error} + +
+ )} + {entries.length === 0 ? ( +
+

No entries found. Press the "Add phone" button to get started!

+
+ ) : ( + entries.map((entry) => ( + handleEditEntry(entry.id, name, phone, email)} + onDelete={() => handleDeleteEntry(entry.id)} + /> + )) + )}
); } \ No newline at end of file From fad714efebbee279ea944244b84cf434f0a372bb Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 18:01:45 +0300 Subject: [PATCH 27/41] Change the name of the web page --- app/index.html | 4 ++-- app/src/pages/phonebook/phonebookPage.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/index.html b/app/index.html index e4b78ea..0f14b2c 100644 --- a/app/index.html +++ b/app/index.html @@ -4,10 +4,10 @@ - Vite + React + TS + Phonebook
- + \ No newline at end of file diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index 3981a32..b5437f3 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -17,7 +17,7 @@ export function PhonebookPage() { email: string; }[]>([]); const [error, setError] = useState(null); - const [showError, setShowError] = useState(false); // New state for controlling visibility + const [showError, setShowError] = useState(false); useEffect(() => { async function loadEntries() { From 7d0d104e62b5b99d71447d00b3e12b40c6330b3b Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 18:06:39 +0300 Subject: [PATCH 28/41] Return the spacing and flex container for the entry cards --- app/src/pages/phonebook/phonebookPage.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index b5437f3..ab40c29 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -113,6 +113,8 @@ export function PhonebookPage() {

No entries found. Press the "Add phone" button to get started!

) : ( +
+ { entries.map((entry) => ( handleEditEntry(entry.id, name, phone, email)} onDelete={() => handleDeleteEntry(entry.id)} /> - )) - )} + ))} +
) + }
); } \ No newline at end of file From 96160e398e07c7475da1f31e98a045d9114080e9 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 18:15:41 +0300 Subject: [PATCH 29/41] Change the regular expression for phone numbers --- app/src/pages/phonebook/phonebookPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index ab40c29..7b78f7e 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -53,7 +53,7 @@ export function PhonebookPage() { handleError("All fields are required."); return; } - if (!/^\+\d{11,15}$/.test(phone)) { + if (!/^\+\d{11}$/.test(phone)) { handleError("Phone number must be written in the format +XXXXXXXXXXX"); return; } @@ -70,7 +70,7 @@ export function PhonebookPage() { handleError("All fields are required."); return; } - if (!/^\+\d{11,15}$/.test(phone)) { + if (!/^\+\d{11}$/.test(phone)) { handleError("Phone number must be written in the format +XXXXXXXXXXX"); return; } From b8e0be757ae036ffd26e9f74ba2aa094b4954689 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Tue, 29 Apr 2025 23:54:38 +0300 Subject: [PATCH 30/41] Add rudimentary searching --- app/src/pages/phonebook/phonebookPage.tsx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index 7b78f7e..c64ca60 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -7,6 +7,7 @@ import { import { EntryCard } from "@/components/phonebook/EntryCard"; import { AddEntry } from "@/components/phonebook/AddEntry"; import { fetchEntries, addEntry, editEntry, deleteEntry } from "@/services/phonebookService"; +import { Input } from "@/components/ui/input"; import { Terminal } from "lucide-react"; export function PhonebookPage() { @@ -16,6 +17,7 @@ export function PhonebookPage() { phone: string; email: string; }[]>([]); + const [searchQuery, setSearchQuery] = useState(""); const [error, setError] = useState(null); const [showError, setShowError] = useState(false); @@ -93,12 +95,27 @@ export function PhonebookPage() { } }; + const filteredEntries = entries.filter((entry) => + entry.name.toLowerCase().includes(searchQuery.toLowerCase()) || + entry.phone.includes(searchQuery) || + entry.email.toLowerCase().includes(searchQuery.toLowerCase()) + ); + return (

My Phonebook

+
+ setSearchQuery(e.target.value)} + className="w-full max-w-md mx-auto" + /> +
{error && (
@@ -108,14 +125,14 @@ export function PhonebookPage() {
)} - {entries.length === 0 ? ( + {filteredEntries.length === 0 ? (
-

No entries found. Press the "Add phone" button to get started!

+

No matching entries found.

) : (
{ - entries.map((entry) => ( + filteredEntries.map((entry) => ( Date: Wed, 30 Apr 2025 00:02:57 +0300 Subject: [PATCH 31/41] Change the entry cards shown at start --- app/src/components/phonebook/AddEntry.tsx | 2 +- app/src/pages/phonebook/phonebookPage.tsx | 32 +++++++++-------------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/app/src/components/phonebook/AddEntry.tsx b/app/src/components/phonebook/AddEntry.tsx index 598e4b5..0e51170 100644 --- a/app/src/components/phonebook/AddEntry.tsx +++ b/app/src/components/phonebook/AddEntry.tsx @@ -63,7 +63,7 @@ export function AddEntry({ onAdd }: { onAdd: (name: string, phone: string, email setEmail(e.target.value)} // Fixed the bug here + onChange={(e) => setEmail(e.target.value)} className="col-span-3" />
diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index c64ca60..16e168b 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -125,25 +125,19 @@ export function PhonebookPage() {
)} - {filteredEntries.length === 0 ? ( -
-

No matching entries found.

-
- ) : ( -
- { - filteredEntries.map((entry) => ( - handleEditEntry(entry.id, name, phone, email)} - onDelete={() => handleDeleteEntry(entry.id)} - /> - ))} -
) - } +
+ { + filteredEntries.map((entry) => ( + handleEditEntry(entry.id, name, phone, email)} + onDelete={() => handleDeleteEntry(entry.id)} + /> + ))} +
); } \ No newline at end of file From 0ad125696a68f8815350719dea6b854e3f1f0141 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Wed, 30 Apr 2025 01:45:25 +0300 Subject: [PATCH 32/41] Change filtering --- app/package.json | 2 +- app/src/pages/phonebook/phonebookPage.tsx | 34 +++++++++++++---------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/app/package.json b/app/package.json index 0e42d1a..c40a426 100644 --- a/app/package.json +++ b/app/package.json @@ -10,9 +10,9 @@ "preview": "vite preview" }, "dependencies": { - "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-dialog": "^1.1.11", "@radix-ui/react-label": "^2.1.4", + "@radix-ui/react-slot": "^1.2.0", "@tailwindcss/vite": "^4.1.4", "axios": "^1.8.4", "class-variance-authority": "^0.7.1", diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index 16e168b..7e78678 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -95,6 +95,7 @@ export function PhonebookPage() { } }; + const filteredEntries = entries.filter((entry) => entry.name.toLowerCase().includes(searchQuery.toLowerCase()) || entry.phone.includes(searchQuery) || @@ -105,7 +106,7 @@ export function PhonebookPage() {

My Phonebook

- +
)} -
- { - filteredEntries.map((entry) => ( - handleEditEntry(entry.id, name, phone, email)} - onDelete={() => handleDeleteEntry(entry.id)} - /> - ))} -
+ {entries.length > 0 && filteredEntries.length === 0 ? ( +
+

No matching entries found.

+
+ ) : ( +
+ {filteredEntries.map((entry) => ( + handleEditEntry(entry.id, name, phone, email)} + onDelete={() => handleDeleteEntry(entry.id)} + /> + ))} +
+ )}
); } \ No newline at end of file From f8247d067ac3ad47c40590930303ed264d59e29a Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Wed, 30 Apr 2025 01:48:26 +0300 Subject: [PATCH 33/41] Change filtering --- app/src/pages/phonebook/phonebookPage.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index 7e78678..7b27b67 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -95,18 +95,19 @@ export function PhonebookPage() { } }; - - const filteredEntries = entries.filter((entry) => - entry.name.toLowerCase().includes(searchQuery.toLowerCase()) || - entry.phone.includes(searchQuery) || - entry.email.toLowerCase().includes(searchQuery.toLowerCase()) - ); + const filteredEntries = searchQuery + ? entries.filter((entry) => + entry.name.toLowerCase().includes(searchQuery.toLowerCase()) || + entry.phone.includes(searchQuery) || + entry.email.toLowerCase().includes(searchQuery.toLowerCase()) + ) + : entries; return (

My Phonebook

- +
Date: Wed, 30 Apr 2025 01:53:01 +0300 Subject: [PATCH 34/41] Add debug statement --- app/src/pages/phonebook/phonebookPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index 7b27b67..f9b5d9b 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -31,6 +31,7 @@ export function PhonebookPage() { phone: string; email: string; }[]; + console.log("Fetched entries:", flatData); setEntries(flatData); } catch (err) { handleError("Failed to load entries."); From bb19f6ed2f75f37e95459beb557454a094430b04 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Wed, 30 Apr 2025 01:59:43 +0300 Subject: [PATCH 35/41] Fix filtering again --- app/src/pages/phonebook/phonebookPage.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index f9b5d9b..c188d32 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -22,7 +22,7 @@ export function PhonebookPage() { const [showError, setShowError] = useState(false); useEffect(() => { - async function loadEntries() { + const loadEntries = async () => { try { const data = await fetchEntries(); const flatData = Object.values(data).flat() as { @@ -31,13 +31,14 @@ export function PhonebookPage() { phone: string; email: string; }[]; - console.log("Fetched entries:", flatData); + console.log("Fetched entries:", flatData); // Debug statement setEntries(flatData); } catch (err) { handleError("Failed to load entries."); } - } - loadEntries(); + }; + + loadEntries(); // Call the async function }, []); const handleError = (message: string) => { From 4d3104fa512fe3889adbdd15035ea2d8dd538e2a Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Wed, 30 Apr 2025 02:03:05 +0300 Subject: [PATCH 36/41] Debug entry loading --- app/src/pages/phonebook/phonebookPage.tsx | 37 +++++++++++++++++------ 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index c188d32..ef2d5a8 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -97,13 +97,13 @@ export function PhonebookPage() { } }; - const filteredEntries = searchQuery - ? entries.filter((entry) => - entry.name.toLowerCase().includes(searchQuery.toLowerCase()) || - entry.phone.includes(searchQuery) || - entry.email.toLowerCase().includes(searchQuery.toLowerCase()) - ) - : entries; + // const filteredEntries = searchQuery + // ? entries.filter((entry) => + // entry.name.toLowerCase().includes(searchQuery.toLowerCase()) || + // entry.phone.includes(searchQuery) || + // entry.email.toLowerCase().includes(searchQuery.toLowerCase()) + // ) + // : entries; return (
@@ -129,7 +129,7 @@ export function PhonebookPage() {
)} - {entries.length > 0 && filteredEntries.length === 0 ? ( + {/* {entries.length > 0 && filteredEntries.length === 0 ? (

No matching entries found.

@@ -146,7 +146,26 @@ export function PhonebookPage() { /> ))}
- )} + )} */} + {entries.length === 0 ? ( +
+

No entries found. Press the "Add phone" button to get started!

+
+ ) : ( +
+ { + entries.map((entry) => ( + handleEditEntry(entry.id, name, phone, email)} + onDelete={() => handleDeleteEntry(entry.id)} + /> + ))} +
) + }
); } \ No newline at end of file From 33155cb1880d6f62bd87720c079ad46edde99c11 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Wed, 30 Apr 2025 02:06:56 +0300 Subject: [PATCH 37/41] Add final filtering version --- app/src/pages/phonebook/phonebookPage.tsx | 37 ++++++----------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index ef2d5a8..c188d32 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -97,13 +97,13 @@ export function PhonebookPage() { } }; - // const filteredEntries = searchQuery - // ? entries.filter((entry) => - // entry.name.toLowerCase().includes(searchQuery.toLowerCase()) || - // entry.phone.includes(searchQuery) || - // entry.email.toLowerCase().includes(searchQuery.toLowerCase()) - // ) - // : entries; + const filteredEntries = searchQuery + ? entries.filter((entry) => + entry.name.toLowerCase().includes(searchQuery.toLowerCase()) || + entry.phone.includes(searchQuery) || + entry.email.toLowerCase().includes(searchQuery.toLowerCase()) + ) + : entries; return (
@@ -129,7 +129,7 @@ export function PhonebookPage() {
)} - {/* {entries.length > 0 && filteredEntries.length === 0 ? ( + {entries.length > 0 && filteredEntries.length === 0 ? (

No matching entries found.

@@ -146,26 +146,7 @@ export function PhonebookPage() { /> ))}
- )} */} - {entries.length === 0 ? ( -
-

No entries found. Press the "Add phone" button to get started!

-
- ) : ( -
- { - entries.map((entry) => ( - handleEditEntry(entry.id, name, phone, email)} - onDelete={() => handleDeleteEntry(entry.id)} - /> - ))} -
) - } + )}
); } \ No newline at end of file From e9b684a3059aa355baa1eaf73ec3e426118c4c93 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Wed, 30 Apr 2025 02:18:05 +0300 Subject: [PATCH 38/41] Add theme changer and delete debug statements --- app/src/pages/phonebook/phonebookPage.tsx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index c188d32..1dd52f4 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -4,6 +4,7 @@ import { AlertDescription, AlertTitle, } from "@/components/ui/alert"; +import { Button } from "@/components/ui/button"; import { EntryCard } from "@/components/phonebook/EntryCard"; import { AddEntry } from "@/components/phonebook/AddEntry"; import { fetchEntries, addEntry, editEntry, deleteEntry } from "@/services/phonebookService"; @@ -20,6 +21,7 @@ export function PhonebookPage() { const [searchQuery, setSearchQuery] = useState(""); const [error, setError] = useState(null); const [showError, setShowError] = useState(false); + const [isDarkMode, setIsDarkMode] = useState(false); useEffect(() => { const loadEntries = async () => { @@ -31,16 +33,23 @@ export function PhonebookPage() { phone: string; email: string; }[]; - console.log("Fetched entries:", flatData); // Debug statement setEntries(flatData); } catch (err) { handleError("Failed to load entries."); } }; - loadEntries(); // Call the async function + loadEntries(); }, []); + useEffect(() => { + if (isDarkMode) { + document.documentElement.classList.add("dark"); + } else { + document.documentElement.classList.remove("dark"); + } + }, [isDarkMode]); + const handleError = (message: string) => { setError(message); setShowError(true); @@ -109,7 +118,12 @@ export function PhonebookPage() {

My Phonebook

- +
+ + +
setSearchQuery(e.target.value)} className="w-full max-w-md mx-auto" /> +
+
+
{error && (
From 690050bc5cd57fee50f45620150480d679bc04c2 Mon Sep 17 00:00:00 2001 From: aequor-cntrl <53840534+aequor-cntrl@users.noreply.github.com> Date: Wed, 30 Apr 2025 02:34:58 +0300 Subject: [PATCH 39/41] Changed color palette and added theme button --- app/src/components/phonebook/EntryCard.tsx | 26 ++++++++++++---------- app/src/pages/phonebook/phonebookPage.tsx | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/app/src/components/phonebook/EntryCard.tsx b/app/src/components/phonebook/EntryCard.tsx index 0658104..64cb79e 100644 --- a/app/src/components/phonebook/EntryCard.tsx +++ b/app/src/components/phonebook/EntryCard.tsx @@ -19,20 +19,22 @@ export function EntryCard({ name, phone, email, onEdit, onDelete }: EntryCardPro }; return ( -
+
-

{name}

+

{name}

{phone}

-

{email}

- - +

{email}

+
+ + +
); diff --git a/app/src/pages/phonebook/phonebookPage.tsx b/app/src/pages/phonebook/phonebookPage.tsx index 1dd52f4..d1a4c4b 100644 --- a/app/src/pages/phonebook/phonebookPage.tsx +++ b/app/src/pages/phonebook/phonebookPage.tsx @@ -116,7 +116,7 @@ export function PhonebookPage() { return (
-
+

My Phonebook