commit ed924ef2aced0213897aa6ce523f22ad81041739 Author: Clinton Moss Date: Fri Apr 3 12:35:13 2026 +0200 Add Webapp diff --git a/webapp/.gitignore b/webapp/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/webapp/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/webapp/.vscode/launch.json b/webapp/.vscode/launch.json new file mode 100644 index 0000000..9f5d3a7 --- /dev/null +++ b/webapp/.vscode/launch.json @@ -0,0 +1,45 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Next.js: debug server-side", + "type": "node-terminal", + "request": "launch", + "command": "npm run dev -- --inspect" + }, + { + "name": "Next.js: debug client-side", + "type": "chrome", + "request": "launch", + "url": "http://localhost:3000" + }, + { + "name": "Next.js: debug client-side (Firefox)", + "type": "firefox", + "request": "launch", + "url": "http://localhost:3000", + "reAttach": true, + "pathMappings": [ + { + "url": "webpack://_N_E", + "path": "${workspaceFolder}" + } + ] + }, + { + "name": "Next.js: debug full stack", + "type": "node", + "request": "launch", + "program": "${workspaceFolder}/node_modules/next/dist/bin/next", + "runtimeArgs": ["--inspect"], + "skipFiles": ["/**"], + "serverReadyAction": { + "action": "debugWithEdge", + "killOnServerStop": true, + "pattern": "- Local:.+(https?://.+)", + "uriFormat": "%s", + "webRoot": "${workspaceFolder}" + } + } + ] +} \ No newline at end of file diff --git a/webapp/BUILD.ps1 b/webapp/BUILD.ps1 new file mode 100644 index 0000000..dd4c86d --- /dev/null +++ b/webapp/BUILD.ps1 @@ -0,0 +1,25 @@ +# echo "Building" +## PSVersionTable.PSVersion +## winget install --id Microsoft.Powershell --source winget + +mkdir dist +npm run build +cp -r .next/static .next/standalone/CoffeeChat/portal/.next +cp -r .next/standalone/CoffeeChat/portal dist +Compress-Archive -Path dist -DestinationPath dist.zip -Force +Remove-Item dist -Recurse -Force + +# Create an SSH session +#$remoteUser = "cinton" +#$remoteHost = "rootbranch.co.za:922" +#$session = New-PSSession -HostName "rootbranch.co.za:922" -UserName "cinton" -SSHTransport + +# Copy file from Windows to Linux +#Copy-Item -Path dist.zip -Destination "/home/clinton/dist.zip" -ToSession $session + +# Copy file from Linux to Windows +# Copy-Item -Path "/home/username/file.txt" -Destination "C:\path\to\local\file.txt" -FromSession $session + +# Close the session +#Remove-PSSession $session + diff --git a/webapp/README.md b/webapp/README.md new file mode 100644 index 0000000..1a59266 --- /dev/null +++ b/webapp/README.md @@ -0,0 +1,42 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. + + +## Publish + +npm config set @test:registry=https://gitea.example.com/api/packages/testuser/npm/ +npm config set -- '//gitea.example.com/api/packages/testuser/npm/:_authToken' "personal_access_token" \ No newline at end of file diff --git a/webapp/actions/auth/AuthActions.ts b/webapp/actions/auth/AuthActions.ts new file mode 100644 index 0000000..4cdf4d3 --- /dev/null +++ b/webapp/actions/auth/AuthActions.ts @@ -0,0 +1,35 @@ +"use server"; + +import { CallApi } from "@/helper/api/ApiConnector"; +import { cookies } from "next/headers"; +import { redirect, RedirectType } from "next/navigation"; + +export async function LoginFormAction(formData: FormData) { + console.log(`LoginFormAction`, formData); + const res = await fetch(`http://localhost:8081/api/auth/signin`, { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + email: formData.get("email") as string, + password: formData.get("password") as string, + }), + }).catch((e) => console.error(e)); + // .then(async (res) => { + const resp = await (res as Response).json(); + // console.log(resp) + if (!resp.error) { + const cj = await cookies(); + cj.set("ccsession", resp.result); + redirect(`/dashboard`, RedirectType.replace); + } +} + +export async function RegisterFormAction(formData: FormData) { + await CallApi(`/auth/signup`, "POST", { + name: "", + email: formData.get("email") as string, + password: formData.get("password") as string, + }); +} diff --git a/webapp/actions/room/RoomActions.ts b/webapp/actions/room/RoomActions.ts new file mode 100644 index 0000000..9263389 --- /dev/null +++ b/webapp/actions/room/RoomActions.ts @@ -0,0 +1,7 @@ +'use server' + +import { CallApi } from "@/helper/api/ApiConnector" + +export async function getRooms(){ + return await CallApi("/rooms","GET") +} \ No newline at end of file diff --git a/webapp/actions/users/UserActions.ts b/webapp/actions/users/UserActions.ts new file mode 100644 index 0000000..ef9ce2c --- /dev/null +++ b/webapp/actions/users/UserActions.ts @@ -0,0 +1,8 @@ +"use server"; + +import { CallApi } from "@/helper/api/ApiConnector"; +import { cookies } from "next/headers"; + +export async function ListUsers() { + return await CallApi(`/users`,"GET").catch(e => console.error(e)) +} diff --git a/webapp/app/call/page.tsx b/webapp/app/call/page.tsx new file mode 100644 index 0000000..9c61520 --- /dev/null +++ b/webapp/app/call/page.tsx @@ -0,0 +1,19 @@ +import React from 'react' + +export default function CallScreen() { + return ( +
+
+ + + +
+
+
+
+
Chat
+
+
+ ) +} diff --git a/webapp/app/dashboard/page.tsx b/webapp/app/dashboard/page.tsx new file mode 100644 index 0000000..dc23746 --- /dev/null +++ b/webapp/app/dashboard/page.tsx @@ -0,0 +1,11 @@ +import { ListUsers } from '@/actions/users/UserActions' +import ChatBox from '@/components/chat/ChatBox' +import React from 'react' + +export default async function LoggedIn() { + const users = await ListUsers() + return (<> +
{JSON.stringify(users)}
+ + ) +} diff --git a/webapp/app/favicon.ico b/webapp/app/favicon.ico new file mode 100644 index 0000000..4bed74c Binary files /dev/null and b/webapp/app/favicon.ico differ diff --git a/webapp/app/globals.css b/webapp/app/globals.css new file mode 100644 index 0000000..7c7b4a7 --- /dev/null +++ b/webapp/app/globals.css @@ -0,0 +1,138 @@ +@import "tailwindcss"; +@import "tw-animate-css"; +@import "shadcn/tailwind.css"; + +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-sans); + --font-mono: var(--font-geist-mono); + --font-heading: var(--font-sans); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --radius-sm: calc(var(--radius) * 0.6); + --radius-md: calc(var(--radius) * 0.8); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) * 1.4); + --radius-2xl: calc(var(--radius) * 1.8); + --radius-3xl: calc(var(--radius) * 2.2); + --radius-4xl: calc(var(--radius) * 2.6); +} + +:root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } + html { + @apply font-sans; + } +} + +::view-transition-group(.animate-in){ + animation: animate-in ease-in 0.5s; +} + +::view-transition-group(.animate-out){ + animation: animate-out ease-in 0.5s; +} \ No newline at end of file diff --git a/webapp/app/layout.tsx b/webapp/app/layout.tsx new file mode 100644 index 0000000..c20837d --- /dev/null +++ b/webapp/app/layout.tsx @@ -0,0 +1,65 @@ + +// import React from "react"; + +// export default function RootLayoutClient({ children }) { +// React.useEffect(() => { +// if ("serviceWorker" in navigator) { +// navigator.serviceWorker +// .register("/service-worker.js") +// .then((registration) => { +// console.log("Service Worker registered with scope:", registration.scope); +// }) +// .catch((error) => { +// console.error("Service Worker registration failed:", error); +// }); +// } +// }, []); + +// return ( +//
+//
+// {children} +//
+//
+// ); +// } + +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; +import React from "react"; +import RootLayoutClient from "./layoutClient"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "CoffeeChat", + description: "Start chatting with your communities", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + + return ( + + + + {children} + + + + ); +} diff --git a/webapp/app/layoutClient.tsx b/webapp/app/layoutClient.tsx new file mode 100644 index 0000000..7bd50f6 --- /dev/null +++ b/webapp/app/layoutClient.tsx @@ -0,0 +1,47 @@ +"use client"; + +import React from "react"; + +// import React from "react"; + +// export default function RootLayoutClient({ children }) { +// React.useEffect(() => { +// if ("serviceWorker" in navigator) { +// navigator.serviceWorker +// .register("/service-worker.js") +// .then((registration) => { +// console.log("Service Worker registered with scope:", registration.scope); +// }) +// .catch((error) => { +// console.error("Service Worker registration failed:", error); +// }); +// } +// }, []); + +// return ( +//
+//
+// {children} +//
+//
+// ); +// } +export default function RootLayoutClient({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + React.useEffect(() => { + if ("serviceWorker" in navigator) { + navigator.serviceWorker + .register("/service-worker.js") + .then((registration) => { + console.log("Service Worker registered with scope:", registration.scope); + }) + .catch((error) => { + console.error("Service Worker registration failed:", error); + }); + } + }, []); + return (children); +} diff --git a/webapp/app/login/page.tsx b/webapp/app/login/page.tsx new file mode 100644 index 0000000..8266323 --- /dev/null +++ b/webapp/app/login/page.tsx @@ -0,0 +1,11 @@ +import { LoginForm } from "@/components/login-form" + +export default function Page() { + return ( +
+
+ +
+
+ ) +} diff --git a/webapp/app/manifest.ts b/webapp/app/manifest.ts new file mode 100644 index 0000000..ca82a32 --- /dev/null +++ b/webapp/app/manifest.ts @@ -0,0 +1,81 @@ +import type { MetadataRoute } from "next"; + +export default function manifest(): MetadataRoute.Manifest { + return { + name: "CoffeeChat", + short_name: "CoffeeChat", + start_url: "chat.rootbranch.co.za", + display: "standalone", + description: "Start chatting with your communities", + lang: " en", + dir: "auto", + theme_color: "#59168b", + background_color: "#59168b", + orientation: "any", + icons: [ + { + src: "/manifest-icon-192.maskable.png", + sizes: "192x192", + type: "image/png", + purpose: "any", + }, + { + src: "/manifest-icon-192.maskable.png", + sizes: "192x192", + type: "image/png", + purpose: "maskable", + }, + { + src: "/manifest-icon-512.maskable.png", + sizes: "512x512", + type: "image/png", + purpose: "any", + }, + { + src: "/manifest-icon-512.maskable.png", + sizes: "512x512", + type: "image/png", + purpose: "maskable", + }, + ], + screenshots: [ + { + src: "screen1.png", + sizes: "2880x1800", + type: "image/png", + form_factor: "wide", + label: "Communities Home Page", + }, + { + src: "screen2.png", + sizes: "570x1265", + type: "image/png", + form_factor: "narrow", + label: "Communities Home Page", + }, + ], + related_applications: [ + { + platform: "windows", + url: "https://chat.rootbranch.co.za", + }, + ], + prefer_related_applications: false, + shortcuts: [ + { + name: "CoffeeChat", + url: "chat.rootbranch.co.za", + description: "Start chatting with your communities", + icons: [ + { + src: "manifest-icon-96.maskable.png", + purpose: "any", + sizes: "96x96", + type: "image/png", + }, + ], + }, + ], + display_override: ["fullscreen"], + }; +} diff --git a/webapp/app/page.tsx b/webapp/app/page.tsx new file mode 100644 index 0000000..959b4af --- /dev/null +++ b/webapp/app/page.tsx @@ -0,0 +1,56 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { LoginFormAction } from "@/actions/auth/AuthActions"; +import { getRooms } from "@/actions/room/RoomActions"; +import RoomCard from "@/components/RoomCard"; +import { Handshake } from "lucide-react"; +import { cookies } from "next/headers"; +import Image from "next/image"; +import Link from "next/link"; +import { ViewTransition } from "react"; + +export default async function Home() { + + const cj = await cookies() + const session = cj.get(`ccsession`) + + const rooms = await getRooms() + return ( +
+
+
+ + +
+ {/* + */} + {!session && +
+ Login + + Register + +
+ } +
+
+ {rooms.map((room: { + title: string; + room: string; + image: any; + color: string; + }, i: number) => + + )} +
+ {/* {JSON.stringify(rooms)} */} +
+ ); +} diff --git a/webapp/app/register/error.tsx b/webapp/app/register/error.tsx new file mode 100644 index 0000000..3bcf160 --- /dev/null +++ b/webapp/app/register/error.tsx @@ -0,0 +1,10 @@ +'use client' +import ErrorDialog from '@/components/Dialogs/ErrorDialog' +import React from 'react' + +export default function error({ error }: { error: { message: string } }) { + return ( + + //
error : {JSON.stringify(JSON.parse(error.message).error)}
+ ) +} diff --git a/webapp/app/register/page.tsx b/webapp/app/register/page.tsx new file mode 100644 index 0000000..39b9861 --- /dev/null +++ b/webapp/app/register/page.tsx @@ -0,0 +1,57 @@ +import { RegisterFormAction } from '@/actions/auth/AuthActions' +import Link from 'next/link' +import React, { ViewTransition } from 'react' +// import { ViewTransition } from 'react' +export default function Register() { + return ( + +
+
+ +
+
Register Your Profile
+
+
+
+
+
+ + +
+ This will be used for your records but aliases are allowed while using chats +
+
+
+
+ + +
+ This will be used to login to the system and gain access to restricted groups +
+
+
+
+ + +
+
+
+
+
+ + + + +
+ {/* + +
+ */} + +
+ +
+ ) +} diff --git a/webapp/app/signup/page.tsx b/webapp/app/signup/page.tsx new file mode 100644 index 0000000..34ced2d --- /dev/null +++ b/webapp/app/signup/page.tsx @@ -0,0 +1,11 @@ +import { SignupForm } from "@/components/signup-form" + +export default function Page() { + return ( +
+
+ +
+
+ ) +} diff --git a/webapp/app/tesst/page.tsx b/webapp/app/tesst/page.tsx new file mode 100644 index 0000000..f0a5751 --- /dev/null +++ b/webapp/app/tesst/page.tsx @@ -0,0 +1,10 @@ +import MediaSoupWidget from '@/components/chat/MediaSoupWidget' +import WebRTCChat from '@/components/chat/WebRTCChatUsingPeer' +import React from 'react' + +export default function Tttest() { + return ( +
+ //
+ ) +} diff --git a/webapp/app/testb/page.tsx b/webapp/app/testb/page.tsx new file mode 100644 index 0000000..1dcf91a --- /dev/null +++ b/webapp/app/testb/page.tsx @@ -0,0 +1,16 @@ +import ChatNoServerWidget from '@/components/chat/ChatNoServerWidget' +import ChatWS from '@/components/chat/ChatWS' +import MediaSoupWidget from '@/components/chat/MediaSoupWidget' +import WebRTCChatUsingPeer from '@/components/chat/WebRTCChatUsingPeer' +import WebRTCChat from '@/components/chat/WebRTCChatUsingPeer' +import WebRTComponent from '@/components/chat/WebRTComponent' +import React from 'react' + +export default function Tttest() { + return ( + //
+ //
+ //
+
+ ) +} diff --git a/webapp/app/testc/page.tsx b/webapp/app/testc/page.tsx new file mode 100644 index 0000000..341cd90 --- /dev/null +++ b/webapp/app/testc/page.tsx @@ -0,0 +1,33 @@ +import Link from 'next/link' +import React from 'react' + +export default function Search() { + return ( +
+
+ + +
+
+ + + + +
+
+ ) +} + + +function RoomCard({ + title, + room, +}: { + title: string + room: string +}) { + return
{title}
+} \ No newline at end of file diff --git a/webapp/app/testd/page.tsx b/webapp/app/testd/page.tsx new file mode 100644 index 0000000..61d8511 --- /dev/null +++ b/webapp/app/testd/page.tsx @@ -0,0 +1,98 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +'use client' +import RoomCard from '@/components/RoomCard' +import { CallApi } from '@/helper/api/ApiConnector' +import Link from 'next/link' +import React, { useState } from 'react' + +export default function Search() { + const [details, setDetails] = useState<{ + id?: number; + image: any, + title: string, + room: string, + color: string + }>() + + const handleSave = async () => { + console.log(await CallApi(`/room`, 'POST', { id: 0, ...details,image: details?.image })) + } + + return ( +
+
+ +
+ +
+ + + + +
+
+ setDetails((d: any) => { + return { ...d, title: e.target.value } + })} + className='text-white w-full border-0 focus:p-2 transition-all focus:border-0' /> + + +
+ + { + const file = e.target.files![0] + if (file && file.type.startsWith('image/')) { + const reader = new FileReader(); // Create a new FileReader instance + + // Set up the onload event for the reader + reader.onload = function (e) { + // e.target.result contains the image data as a Base64 encoded URL (data URL) + console.log('Image Data URL:', e.target!.result); + + // You can now set the src of an image tag to this data URL to display it + setDetails((d: any) => { + return { ...d, image: e.target!.result } + }) + // imagePreview.src = e.target.result; + + // To get pixel data (ImageData object), you would use a canvas element + // (See "Getting Pixel Data" below) + }; + + // Read the image file as a Data URL + reader.readAsDataURL(file); + } else { + // imagePreview.src = '#'; // Clear preview if not an image + console.error('Please select a valid image file.'); + } + }} + className='text-white' type='file' name='image' /> +
+
+ + setDetails((d: any) => { + return { ...d, color: e.target.value } + })} + type='color' name='color' /> +
+ {details && } +
+
+
+
+ ) +} + diff --git a/webapp/app/teste/page.tsx b/webapp/app/teste/page.tsx new file mode 100644 index 0000000..be96340 --- /dev/null +++ b/webapp/app/teste/page.tsx @@ -0,0 +1,38 @@ +import Link from 'next/link' +import React from 'react' + +export default function Profile() { + return ( +
+
+ +
+ +
+ + + + +
+ +
+
+
+ ) +} + + +function RoomCard({ + title, + room, +}: { + title: string + room: string +}) { + return
{title}
+} \ No newline at end of file diff --git a/webapp/components.json b/webapp/components.json new file mode 100644 index 0000000..02e61e0 --- /dev/null +++ b/webapp/components.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "radix-nova", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "rtl": false, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "menuColor": "default", + "menuAccent": "subtle", + "registries": {} +} diff --git a/webapp/components/Dialogs/ErrorDialog.tsx b/webapp/components/Dialogs/ErrorDialog.tsx new file mode 100644 index 0000000..1d17082 --- /dev/null +++ b/webapp/components/Dialogs/ErrorDialog.tsx @@ -0,0 +1,7 @@ +import React from 'react' + +export default function ErrorDialog({ error }: { error: string | Error }) { + return ( +
{error instanceof Error ? error.message : error }
+ ) +} diff --git a/webapp/components/RoomCard.tsx b/webapp/components/RoomCard.tsx new file mode 100644 index 0000000..f7b753f --- /dev/null +++ b/webapp/components/RoomCard.tsx @@ -0,0 +1,59 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import Link from "next/link" + +export default function RoomCard({ + title, + room, + image, + color, +}: { + title: string + room: string + image: any, + color: string +}) { + if(!image) return "No Image Available" + return + {image &&
+ +
{title}
+ + +
+
+
+ + } + + +} \ No newline at end of file diff --git a/webapp/components/chat/ChatBox.tsx b/webapp/components/chat/ChatBox.tsx new file mode 100644 index 0000000..35be861 --- /dev/null +++ b/webapp/components/chat/ChatBox.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import { Input } from '../ui/input' +import { InputGroup, InputGroupAddon, InputGroupButton } from '../ui/input-group' +import { Textarea } from '../ui/textarea' + +export default function ChatBox() { + return ( +
+
+ CHAT MESSAGES +
Placeholder message
+
Placeholder message
+
+
+
+ +