feat: update Next.js configuration, add 'use client' directive to multiple components, and create new pages for music, editor, and videos
Some checks failed
GBCI / build (push) Failing after 1m45s

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-04-27 15:25:45 -03:00
parent f3a659f8b0
commit 4e57232f08
31 changed files with 114 additions and 132 deletions

View file

@ -1,20 +0,0 @@
import { NextResponse } from 'next/server'
export async function POST() {
try {
const response = await fetch('https://generalbots.online/directline/PROD-GeneralBots006/conversations', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
})
const data = await response.json()
return NextResponse.json(data)
} catch (error) {
return NextResponse.json(
{ error: 'Failed to create conversation' },
{ status: 500 }
)
}
}

View file

@ -1,14 +0,0 @@
import { NextResponse } from 'next/server'
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const room = searchParams.get('room')
const identity = searchParams.get('identity')
const response = await fetch(
`https://generalbots.online/PROD-GeneralBots006/meeting-token?room=${room}&identity=${identity}`
)
const data = await response.json()
return NextResponse.json(data)
}

View file

@ -6,7 +6,6 @@ import '../../styles/chat.css';
export function ChatInput() { export function ChatInput() {
const [message, setMessage] = React.useState(''); const [message, setMessage] = React.useState('');
const [showEmoji, setShowEmoji] = React.useState(false);
const { sendActivity } = useChat(); const { sendActivity } = useChat();
const { playSound } = useSound(); const { playSound } = useSound();
@ -20,10 +19,6 @@ export function ChatInput() {
setMessage(''); setMessage('');
}; };
const handleEmojiSelect = (emoji) => {
playSound('click');
setMessage((prev) => prev + emoji);
};
return ( return (
<> <>
@ -33,7 +28,7 @@ export function ChatInput() {
<path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" /> <path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" />
</svg> </svg>
</button> </button>
<button className="icon-button" onClick={() => setShowEmoji(true)}> <button className="icon-button">
<svg className="icon" viewBox="0 0 24 24"> <svg className="icon" viewBox="0 0 24 24">
<path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zM8 14s1.5 2 4 2 4-2 4-2M9 9h.01M15 9h.01" /> <path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zM8 14s1.5 2 4 2 4-2 4-2M9 9h.01M15 9h.01" />
</svg> </svg>

View file

@ -1,6 +1,6 @@
"use client"; "use client";
import React, { createContext, useContext, useState, useEffect } from 'react'; import React, { createContext, useContext, useState, useEffect } from 'react';
import { User, ChatInstance } from '../types'; import { User } from '../types';
const ChatContext = createContext(undefined); const ChatContext = createContext(undefined);
@ -28,8 +28,8 @@ export function ChatProvider({ children }) {
const chatService = { const chatService = {
activity$: { subscribe: () => {} }, activity$: { subscribe: () => {} },
postActivity: (activity) => ({ postActivity: () => ({
subscribe: (observer) => { subscribe: () => {
return { unsubscribe: () => {} }; return { unsubscribe: () => {} };
}, },
}), }),

View file

@ -1,12 +1,12 @@
"use client"; "use client";
import React, { createContext, useContext, useCallback } from 'react'; import React, { createContext, useCallback } from 'react';
const SoundContext = createContext(undefined); const SoundContext = createContext(undefined);
export function SoundProvider({ children }) { export function SoundProvider({ children }) {
const [enabled, setEnabled] = React.useState(true); const [enabled, setEnabled] = React.useState(true);
const playSound = useCallback((sound) => { const playSound = useCallback(() => {
if (!enabled) return; if (!enabled) return;
const audio = new Audio(); const audio = new Audio();
audio.play().catch((err) => console.error('Failed to play sound:', err)); audio.play().catch((err) => console.error('Failed to play sound:', err));

View file

@ -0,0 +1,8 @@
'use client'
export default function MainPage() {
return (
<div className="flex flex-col h-screen bg-gray-50">
</div>
)
}

View file

@ -1,5 +1,4 @@
import { ThemeProvider } from "@/components/ui/theme-provider"; import { ThemeProvider } from "@/components/ui/theme-provider";
import { Metadata } from 'next';
import { Nav } from './client-nav'; import { Nav } from './client-nav';
import './globals.css'; import './globals.css';

View file

@ -42,7 +42,7 @@ import {
TooltipContent, TooltipContent,
TooltipTrigger, TooltipTrigger,
} from "@/components/ui/tooltip" } from "@/components/ui/tooltip"
import { Mail } from "./data" import { Mail } from "../data"
interface MailDisplayProps { interface MailDisplayProps {
mail: Mail | null mail: Mail | null

View file

@ -1,7 +1,6 @@
"use client" "use client"
import NextLink from 'next/link'; // Changed from lucide-react import NextLink from 'next/link'; // Changed from lucide-react
import { Link as LinkIcon } from 'lucide-react'; // Renamed to avoid conflict
import { LucideIcon } from "lucide-react" import { LucideIcon } from "lucide-react"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"

View file

@ -1,4 +1,3 @@
import Image from "next/image"
import { Mail } from "./components/mail" import { Mail } from "./components/mail"
import { accounts, mails } from "./data" import { accounts, mails } from "./data"

View file

@ -3,8 +3,6 @@
import { useState, useEffect, useRef } from 'react' import { useState, useEffect, useRef } from 'react'
import { LiveKitRoom, VideoConference } from '@livekit/components-react' import { LiveKitRoom, VideoConference } from '@livekit/components-react'
import { RoomEvent, Track } from 'livekit-client'
import { useRouter } from 'next/navigation'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Card } from '@/components/ui/card' import { Card } from '@/components/ui/card'
@ -12,11 +10,15 @@ import { ScrollArea } from '@/components/ui/scroll-area'
import '@livekit/components-styles'; import '@livekit/components-styles';
import { Avatar, AvatarFallback } from '@/components/ui/avatar' import { Avatar, AvatarFallback } from '@/components/ui/avatar'
import { Mic, MicOff, Video, VideoOff, Send, Bot } from 'lucide-react' import { Mic, MicOff, Video, VideoOff, Send, Bot } from 'lucide-react'
import { useRouter } from 'next/router'
export default function MeetingPage({ params }: { params: { room: string } }) { export default function MeetRoomPage() {
const [name, setName] = useState('');
const router = useRouter() const router = useRouter()
const [name, setName] = useState('')
const [roomName, setRoomName] = useState(params.room || '') const [roomName, setRoomName] = useState(router.query.slug || '');
const [token, setToken] = useState('') const [token, setToken] = useState('')
const [isConnected, setIsConnected] = useState(false) const [isConnected, setIsConnected] = useState(false)
const [messages, setMessages] = useState<Array<{ sender: string, text: string, isBot: boolean }>>([]) const [messages, setMessages] = useState<Array<{ sender: string, text: string, isBot: boolean }>>([])
@ -25,15 +27,12 @@ export default function MeetingPage({ params }: { params: { room: string } }) {
const [cameraEnabled, setCameraEnabled] = useState(true) const [cameraEnabled, setCameraEnabled] = useState(true)
const [botTyping, setBotTyping] = useState(false) const [botTyping, setBotTyping] = useState(false)
const botConnectionRef = useRef<any>(null) const botConnectionRef = useRef<any>(null)
const audioContextRef = useRef<AudioContext>()
const processorRef = useRef<ScriptProcessorNode>()
const participantsRef = useRef<Map<string, MediaStreamAudioSourceNode>>(new Map())
// Connect to LiveKit room // Connect to LiveKit room
const connectToRoom = async () => { const connectToRoom = async () => {
try { try {
const resp = await fetch(`/api/get-token?room=${roomName}&identity=${name || 'user'}`) const resp = await fetch(`https://generalbots.online/PROD-GeneralBots006/meeting-token?room=${roomName}&identity=${name || 'user'}`)
const data = await resp.json() const data = await resp.json()
setToken(data.token) setToken(data.token)
setIsConnected(true) setIsConnected(true)
@ -48,19 +47,15 @@ export default function MeetingPage({ params }: { params: { room: string } }) {
// Connect to Bot Framework via Next.js API proxy // Connect to Bot Framework via Next.js API proxy
const connectBot = async () => { const connectBot = async () => {
try { try {
// First create a conversation through our API proxy
const convResponse = await fetch('/api/bot/create-conversation', { const response = await fetch('https://generalbots.online/directline/PROD-GeneralBots006/conversations', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}); })
const convData = await convResponse.json(); const data = await response.json()
if (!convData.conversationId) {
throw new Error('Failed to create conversation');
}
// Then connect using WebSocket (which doesn't have CORS restrictions) // Then connect using WebSocket (which doesn't have CORS restrictions)
const { DirectLine } = await import('botframework-directlinejs') const { DirectLine } = await import('botframework-directlinejs')
@ -68,8 +63,8 @@ export default function MeetingPage({ params }: { params: { room: string } }) {
botConnectionRef.current = new DirectLine({ botConnectionRef.current = new DirectLine({
domain: 'https://generalbots.online/directline/PROD-GeneralBots006', domain: 'https://generalbots.online/directline/PROD-GeneralBots006',
conversationId: convData.conversationId,
userId: userId, userId: userId,
conversationId: data.conversationId,
webSocket: false // Force WebSocket connection webSocket: false // Force WebSocket connection
} as any); } as any);
botConnectionRef.current.setUserId(userId); botConnectionRef.current.setUserId(userId);
@ -189,7 +184,7 @@ export default function MeetingPage({ params }: { params: { room: string } }) {
<VideoConference className="absolute inset-0" /> <VideoConference className="absolute inset-0" />
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex gap-2 bg-gray-800/80 backdrop-blur-sm p-2 rounded-full"> <div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex gap-2 bg-gray-800/80 backdrop-blur-sm p-2 rounded-full">
<Button <Button
variant={micEnabled ? 'primary' : 'outline'} variant={micEnabled ? 'link' : 'outline'}
size="icon" size="icon"
onClick={() => setMicEnabled(!micEnabled)} onClick={() => setMicEnabled(!micEnabled)}
className="rounded-full h-10 w-10 hover:bg-gray-700 transition-colors" className="rounded-full h-10 w-10 hover:bg-gray-700 transition-colors"
@ -197,7 +192,7 @@ export default function MeetingPage({ params }: { params: { room: string } }) {
{micEnabled ? <Mic className="h-5 w-5" /> : <MicOff className="h-5 w-5" />} {micEnabled ? <Mic className="h-5 w-5" /> : <MicOff className="h-5 w-5" />}
</Button> </Button>
<Button <Button
variant={cameraEnabled ? 'primary' : 'outline'} variant={cameraEnabled ? 'link' : 'outline'}
size="icon" size="icon"
onClick={() => setCameraEnabled(!cameraEnabled)} onClick={() => setCameraEnabled(!cameraEnabled)}
className="rounded-full h-10 w-10 hover:bg-gray-700 transition-colors" className="rounded-full h-10 w-10 hover:bg-gray-700 transition-colors"

View file

@ -0,0 +1,8 @@
'use client'
export default function MainPage() {
return (
<div className="flex flex-col h-screen bg-gray-50">
</div>
)
}

View file

@ -1,3 +1,6 @@
"use client";
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useForm, Controller } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod'; import { z } from 'zod';

View file

@ -1,3 +1,4 @@
"use client";
import React from 'react'; import React from 'react';
import { AccountForm } from './account-form'; import { AccountForm } from './account-form';

View file

@ -1,3 +1,5 @@
"use client";
import React from 'react'; import React from 'react';
import { useForm, Controller } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod'; import { z } from 'zod';

View file

@ -1,3 +1,5 @@
"use client";
import React from 'react'; import React from 'react';
import { AppearanceForm } from './appearance-form'; import { AppearanceForm } from './appearance-form';

View file

@ -1,5 +1,7 @@
'use client'; // Required for client-side interactivity
import { usePathname, useRouter } from 'next/navigation';
import React from 'react'; import React from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
interface SidebarNavProps { interface SidebarNavProps {
items: { items: {
@ -9,17 +11,17 @@ interface SidebarNavProps {
} }
export function SidebarNav({ items }: SidebarNavProps) { export function SidebarNav({ items }: SidebarNavProps) {
const navigate = useNavigate(); const router = useRouter();
const location = useLocation(); const pathname = usePathname();
return ( return (
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{items.map((item) => ( {items.map((item) => (
<button <button
key={item.href} key={item.href}
onClick={() => navigate(item.href)} onClick={() => router.push(item.href)}
className={`px-3 py-2 rounded-md text-sm font-medium ${ className={`px-3 py-2 rounded-md text-sm font-medium ${
location.pathname === item.href ? 'bg-gray-100' : 'hover:bg-gray-50' pathname === item.href ? 'bg-gray-100' : 'hover:bg-gray-50'
}`} }`}
> >
{item.title} {item.title}

View file

@ -1,3 +1,6 @@
"use client";
import React from 'react'; import React from 'react';
import { useForm, Controller } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod'; import { z } from 'zod';

View file

@ -1,3 +1,5 @@
"use client";
import React from 'react'; import React from 'react';
import { DisplayForm } from './display-form'; import { DisplayForm } from './display-form';

View file

@ -1,3 +1,5 @@
"use client";
import React from 'react'; import React from 'react';
import { useForm, Controller } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod'; import { z } from 'zod';

View file

@ -1,3 +1,5 @@
"use client";
import React from 'react'; import React from 'react';
import { NotificationsForm } from './notifications-form'; import { NotificationsForm } from './notifications-form';

View file

@ -1,3 +1,5 @@
"use client";
import React from 'react'; import React from 'react';
import { useForm, Controller } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod'; import { z } from 'zod';

View file

@ -60,13 +60,13 @@ function Page() {
const config: RcloneConfig = { const config: RcloneConfig = {
name: state.name, name: state.name,
remote_path: `s3://${state.name}`, remote_path: `s3://${state.name}`,
local_path: `${window.__TAURI__.path.homeDir}/General Bots/${state.name}`, local_path: `${window['__TAURI__'].path.homeDir}/General Bots/${state.name}`,
access_key: state.access_key, access_key: state.access_key,
secret_key: state.secret_key, secret_key: state.secret_key,
}; };
try { try {
await core.invoke("save_config", { config }); await invoke("save_config", { config });
setState(prev => ({ setState(prev => ({
...prev, ...prev,
status_text: "New sync saved!", status_text: "New sync saved!",
@ -85,13 +85,13 @@ function Page() {
const config: RcloneConfig = { const config: RcloneConfig = {
name: state.name || "example", name: state.name || "example",
remote_path: `s3://${state.name || "example"}`, remote_path: `s3://${state.name || "example"}`,
local_path: `${window.__TAURI__.path.homeDir}/General Bots/${state.name || "example"}`, local_path: `${window['__TAURI__'].path.homeDir}/General Bots/${state.name || "example"}`,
access_key: state.access_key || "dummy", access_key: state.access_key || "dummy",
secret_key: state.secret_key || "dummy", secret_key: state.secret_key || "dummy",
}; };
try { try {
await core.invoke("start_sync", { config }); await invoke("start_sync", { config });
setState(prev => ({ setState(prev => ({
...prev, ...prev,
status_text: "Sync started!" status_text: "Sync started!"
@ -106,7 +106,7 @@ function Page() {
const stopSync = async () => { const stopSync = async () => {
try { try {
await core.invoke("stop_sync"); await invoke("stop_sync");
setState(prev => ({ setState(prev => ({
...prev, ...prev,
status_text: "Sync stopped." status_text: "Sync stopped."

View file

@ -1,8 +1,6 @@
import { core } from '@tauri-apps/api'; import { core } from '@tauri-apps/api';
import { useState } from 'react'; import { useState } from 'react';
import { api } from '@tauri-apps/api';
interface FileOperationsProps { interface FileOperationsProps {
@ -15,21 +13,6 @@ export function FileOperations({ currentPath, onRefresh }: FileOperationsProps)
const handleUpload = async () => { const handleUpload = async () => {
try { try {
const selected = await open({
multiple: false,
directory: false,
});
if (selected) {
const filePath = Array.isArray(selected) ? selected[0] : selected;
await core.invoke('upload_file', {
srcPath: filePath,
destPath: currentPath,
onProgress: (progress: number) => setUploadProgress(progress)
});
onRefresh();
alert('File uploaded successfully!');
}
} catch (error) { } catch (error) {
console.error('Upload failed:', error); console.error('Upload failed:', error);
alert('Upload failed!'); alert('Upload failed!');

View file

@ -1,5 +1,6 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { core } from '@tauri-apps/api'; import { core } from '@tauri-apps/api';
import { FileBrowser } from './FileBrowser';
interface FileItem { interface FileItem {
name: string; name: string;
@ -47,7 +48,7 @@ export function FileTree({ onSelect }: FileTreeProps) {
</div> </div>
{expanded[item.path] && ( {expanded[item.path] && (
<div className="pl-4"> <div className="pl-4">
<FileBrowser path={item.path} onSelect={onSelect} /> <FileBrowser path={item.path} />
</div> </div>
)} )}
</li> </li>

View file

@ -0,0 +1,8 @@
'use client'
export default function MainPage() {
return (
<div className="flex flex-col h-screen bg-gray-50">
</div>
)
}

View file

@ -1,6 +1,6 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
output: 'export',
images: { unoptimized: true } images: { unoptimized: true }
} }

8
package-lock.json generated
View file

@ -59,7 +59,7 @@
"react": "18.3.1", "react": "18.3.1",
"react-day-picker": "^8.10.1", "react-day-picker": "^8.10.1",
"react-dom": "18.3.1", "react-dom": "18.3.1",
"react-hook-form": "^7.53.2", "react-hook-form": "^7.56.1",
"react-markdown": "10.1.0", "react-markdown": "10.1.0",
"react-resizable-panels": "^2.1.7", "react-resizable-panels": "^2.1.7",
"tailwind-merge": "3.0.2", "tailwind-merge": "3.0.2",
@ -12617,9 +12617,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/react-hook-form": { "node_modules/react-hook-form": {
"version": "7.53.2", "version": "7.56.1",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.2.tgz", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.56.1.tgz",
"integrity": "sha512-YVel6fW5sOeedd1524pltpHX+jgU2u3DSDtXEaBORNdqiNrsX/nUI/iGXONegttg0mJVnfrIkiV0cmTU6Oo2xw==", "integrity": "sha512-qWAVokhSpshhcEuQDSANHx3jiAEFzu2HAaaQIzi/r9FNPm1ioAvuJSD4EuZzWd7Al7nTRKcKPnBKO7sRn+zavQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"

View file

@ -60,7 +60,7 @@
"react": "18.3.1", "react": "18.3.1",
"react-day-picker": "^8.10.1", "react-day-picker": "^8.10.1",
"react-dom": "18.3.1", "react-dom": "18.3.1",
"react-hook-form": "^7.53.2", "react-hook-form": "^7.56.1",
"react-markdown": "10.1.0", "react-markdown": "10.1.0",
"react-resizable-panels": "^2.1.7", "react-resizable-panels": "^2.1.7",
"tailwind-merge": "3.0.2", "tailwind-merge": "3.0.2",

View file

@ -7,5 +7,5 @@ export async function getServerCookie(key: string): Promise<string | undefined>
if (process.env.NEXT_PHASE === 'phase-production-build') { if (process.env.NEXT_PHASE === 'phase-production-build') {
return undefined; return undefined;
} }
return cookies().get(key)?.value; return (await cookies()).get(key)?.value;
} }

File diff suppressed because one or more lines are too long