Phase 2: AI Chat, Calendar, Odoo connector, PWA
- AI Chat endpoint (/api/v1/chat) with Claude API context - Calendar page with FullCalendar.js (day/week/month) - Odoo API connector (import/export/webhook) - PWA manifest + service worker for offline - SW register component Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
67
apps/tasks/app/calendar/page.tsx
Normal file
67
apps/tasks/app/calendar/page.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
'use client';
|
||||
import { useState, useEffect } from 'react';
|
||||
import FullCalendar from '@fullcalendar/react';
|
||||
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||
import timeGridPlugin from '@fullcalendar/timegrid';
|
||||
import interactionPlugin from '@fullcalendar/interaction';
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000';
|
||||
|
||||
interface Task {
|
||||
id: string;
|
||||
title: string;
|
||||
scheduled_at: string | null;
|
||||
due_at: string | null;
|
||||
status: string;
|
||||
group_name: string;
|
||||
group_color: string;
|
||||
}
|
||||
|
||||
export default function CalendarPage() {
|
||||
const [tasks, setTasks] = useState<Task[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`${API_URL}/api/v1/tasks?limit=100`)
|
||||
.then(r => r.json())
|
||||
.then(d => setTasks(d.data || []));
|
||||
}, []);
|
||||
|
||||
const events = tasks
|
||||
.filter((t): t is Task & { scheduled_at: string } | Task & { due_at: string } =>
|
||||
t.scheduled_at !== null || t.due_at !== null
|
||||
)
|
||||
.map(t => ({
|
||||
id: t.id,
|
||||
title: t.title,
|
||||
start: (t.scheduled_at || t.due_at) as string,
|
||||
end: (t.due_at || t.scheduled_at) as string,
|
||||
backgroundColor: t.group_color || '#3B82F6',
|
||||
borderColor: t.group_color || '#3B82F6',
|
||||
extendedProps: { status: t.status, group: t.group_name }
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<h1 className="text-2xl font-bold mb-4">Kalendar</h1>
|
||||
<div className="bg-white dark:bg-gray-800 rounded-xl p-4 shadow">
|
||||
<FullCalendar
|
||||
plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
|
||||
initialView="timeGridWeek"
|
||||
headerToolbar={{
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'dayGridMonth,timeGridWeek,timeGridDay'
|
||||
}}
|
||||
events={events}
|
||||
editable={true}
|
||||
selectable={true}
|
||||
locale="cs"
|
||||
firstDay={1}
|
||||
height="auto"
|
||||
slotMinTime="06:00:00"
|
||||
slotMaxTime="23:00:00"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
10
apps/tasks/app/sw-register.tsx
Normal file
10
apps/tasks/app/sw-register.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
"use client";
|
||||
import { useEffect } from "react";
|
||||
export default function SWRegister() {
|
||||
useEffect(() => {
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker.register("/sw.js").catch(() => {});
|
||||
}
|
||||
}, []);
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user