diff --git a/Channel-Backend/prisma/schema.prisma b/Channel-Backend/prisma/schema.prisma index cced4cb..d84ee8e 100644 --- a/Channel-Backend/prisma/schema.prisma +++ b/Channel-Backend/prisma/schema.prisma @@ -117,15 +117,16 @@ model LegalDocument { } model LegalAcceptance { - id String @id @default(uuid()) - docId String - userId String - ipAddress String - signatureHash String? - documentUrl String? - acceptedAt DateTime @default(now()) - document LegalDocument @relation(fields: [docId], references: [id]) - user User @relation(fields: [userId], references: [id]) + id String @id @default(uuid()) + docId String + userId String + ipAddress String + signatureHash String? + documentUrl String? + signatureBase64 String? + acceptedAt DateTime @default(now()) + document LegalDocument @relation(fields: [docId], references: [id]) + user User @relation(fields: [userId], references: [id]) } model AuditLog { diff --git a/Channel-Backend/src/controllers/legal.controller.ts b/Channel-Backend/src/controllers/legal.controller.ts index 055a730..5b13872 100644 --- a/Channel-Backend/src/controllers/legal.controller.ts +++ b/Channel-Backend/src/controllers/legal.controller.ts @@ -69,7 +69,14 @@ export class LegalController { signatureHash = crypto.createHash('sha256').update(signatureBase64).digest('hex'); } - const acceptance = await this.legalService.recordAcceptance(activeDoc.id, userId, ipAddress, signatureHash || undefined, documentUrl); + const acceptance = await this.legalService.recordAcceptance( + activeDoc.id, + userId, + ipAddress, + signatureHash || undefined, + documentUrl, + signatureBase64 || undefined + ); // Check if they completed all onboarding steps await this.legalService.checkOnboardingCompletion(userId); diff --git a/Channel-Backend/src/services/legal.service.ts b/Channel-Backend/src/services/legal.service.ts index 4087755..d9d30fe 100644 --- a/Channel-Backend/src/services/legal.service.ts +++ b/Channel-Backend/src/services/legal.service.ts @@ -33,10 +33,11 @@ export class LegalService { ipAddress: string, signatureHash?: string, documentUrl?: string, + signatureBase64?: string, ) { // Record acceptance const acceptance = await prisma.legalAcceptance.create({ - data: { docId, userId, ipAddress, signatureHash, documentUrl }, + data: { docId, userId, ipAddress, signatureHash, documentUrl, signatureBase64 }, }); return acceptance; @@ -67,7 +68,15 @@ export class LegalService { public async getAcceptances(userId: string) { return await prisma.legalAcceptance.findMany({ where: { userId }, - include: { document: true }, + select: { + id: true, + signatureHash: true, + documentUrl: true, + signatureBase64: true, + ipAddress: true, + acceptedAt: true, + document: true, + }, }); } @@ -79,7 +88,15 @@ export class LegalService { email: true, createdAt: true, acceptances: { - include: { document: true } + select: { + id: true, + signatureHash: true, + documentUrl: true, + signatureBase64: true, + ipAddress: true, + acceptedAt: true, + document: true, + } } } }); diff --git a/Channel-Frontend/src/App.tsx b/Channel-Frontend/src/App.tsx index 6d993cc..e0bf817 100644 --- a/Channel-Frontend/src/App.tsx +++ b/Channel-Frontend/src/App.tsx @@ -5,6 +5,8 @@ import { useEffect } from 'react'; import { useThemeStore } from './hooks/use-theme'; import { useAuthStore } from './hooks/use-auth'; +import { ToastProvider } from "./components/ui/Toast"; + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: false } @@ -39,7 +41,9 @@ export const App = () => { return ( - + + + ); }; diff --git a/Channel-Frontend/src/app/layouts/AdminLayout.tsx b/Channel-Frontend/src/app/layouts/AdminLayout.tsx index 141a90a..491e0d2 100644 --- a/Channel-Frontend/src/app/layouts/AdminLayout.tsx +++ b/Channel-Frontend/src/app/layouts/AdminLayout.tsx @@ -1,9 +1,22 @@ -import React, { useState } from 'react'; -import { Link, Outlet, useLocation, useNavigate } from 'react-router-dom'; -import { useThemeStore } from '../../hooks/use-theme'; -import { useAuthStore } from '../../hooks/use-auth'; -import { ShieldCheck, BarChart3, ClipboardCheck, FolderGit2, BookCopy, Users, LogOut, Menu, X, Sun, Moon, ChevronRight, ChevronLeft } from 'lucide-react'; -import { motion, AnimatePresence } from 'framer-motion'; +import React, { useState } from "react"; +import { Link, Outlet, useLocation, useNavigate } from "react-router-dom"; +import { useThemeStore } from "../../hooks/use-theme"; +import { useAuthStore } from "../../hooks/use-auth"; +import { + ShieldCheck, + ClipboardCheck, + FolderGit2, + BookCopy, + Users, + LogOut, + Menu, + X, + Sun, + Moon, + ChevronRight, + ChevronLeft, +} from "lucide-react"; +import { motion, AnimatePresence } from "framer-motion"; export const AdminLayout: React.FC = () => { const { user, logout } = useAuthStore(); @@ -15,51 +28,62 @@ export const AdminLayout: React.FC = () => { const handleLogout = () => { logout(); - navigate('/login'); + navigate("/login"); }; const navItems = [ - { name: 'Partners', path: '/admin/partners', icon: Users }, - { name: 'Approvals Queue', path: '/admin/approvals', icon: ClipboardCheck }, - { name: 'Legal Templates', path: '/admin/legal', icon: ShieldCheck }, - { name: 'Manage Catalog', path: '/admin/assets', icon: FolderGit2 }, - { name: 'Analytics', path: '/admin/analytics', icon: BarChart3 }, - { name: 'Blog CMS', path: '/admin/blog', icon: BookCopy } + { name: "Partners", path: "/admin/partners", icon: Users }, + { name: "Approvals Queue", path: "/admin/approvals", icon: ClipboardCheck }, + { name: "Legal Templates", path: "/admin/legal", icon: ShieldCheck }, + { name: "Manage Catalog", path: "/admin/assets", icon: FolderGit2 }, + { name: "Blog CMS", path: "/admin/blog", icon: BookCopy }, ]; return (
- {/* ── Desktop Sidebar ── */} - - - {/* ── Main Content Area ── */} -
+ {/* ── Main Content Area ── */} +
{/* Ambient Glow */}
{/* Mobile Header */} -
+
@@ -161,7 +159,7 @@ export const ClientLayout: React.FC = () => { ))}
- @@ -171,13 +169,13 @@ export const ClientLayout: React.FC = () => { )} -
+
{/* Footer */} -