From f6779fae27e4bf5327b66233d03ab52f6c757165 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Sat, 25 Apr 2026 14:05:02 -0700 Subject: [PATCH] feat: delete inertia app --- example/inertia-app/.gitignore | 13 - example/inertia-app/app/models/Ticket.py | 19 - example/inertia-app/artisan | 8 - example/inertia-app/bootstrap/application.py | 20 - example/inertia-app/config/database.py | 24 - example/inertia-app/config/logging.py | 23 - example/inertia-app/databases/__init__.py | 1 - .../databases/factories/TicketFactory.py | 44 - .../2026_04_21_000001_create_users_table.py | 22 - .../2026_04_21_000002_create_tickets_table.py | 36 - ...6_04_21_000003_create_ticket_tags_table.py | 19 - ..._21_000004_create_ticket_messages_table.py | 28 - .../databases/migrations/__init__.py | 1 - .../databases/seeders/TicketSeeder.py | 11 - .../databases/seeds/database_seeder.py | 6 - example/inertia-app/package.json | 26 - .../inertia-app/providers/fastapi_provider.py | 30 - example/inertia-app/pyproject.toml | 18 - example/inertia-app/resources/css/app.css | 1 - .../resources/js/Pages/Tickets.jsx | 460 ------ .../resources/js/Pages/Welcome.jsx | 72 - example/inertia-app/resources/js/app.jsx | 14 - example/inertia-app/routes/web.py | 25 - example/inertia-app/templates/index.html | 13 - example/inertia-app/uv.lock | 1424 ----------------- example/inertia-app/vite.config.js | 16 - 26 files changed, 2374 deletions(-) delete mode 100644 example/inertia-app/.gitignore delete mode 100644 example/inertia-app/app/models/Ticket.py delete mode 100644 example/inertia-app/artisan delete mode 100644 example/inertia-app/bootstrap/application.py delete mode 100644 example/inertia-app/config/database.py delete mode 100644 example/inertia-app/config/logging.py delete mode 100644 example/inertia-app/databases/__init__.py delete mode 100644 example/inertia-app/databases/factories/TicketFactory.py delete mode 100644 example/inertia-app/databases/migrations/2026_04_21_000001_create_users_table.py delete mode 100644 example/inertia-app/databases/migrations/2026_04_21_000002_create_tickets_table.py delete mode 100644 example/inertia-app/databases/migrations/2026_04_21_000003_create_ticket_tags_table.py delete mode 100644 example/inertia-app/databases/migrations/2026_04_21_000004_create_ticket_messages_table.py delete mode 100644 example/inertia-app/databases/migrations/__init__.py delete mode 100644 example/inertia-app/databases/seeders/TicketSeeder.py delete mode 100644 example/inertia-app/databases/seeds/database_seeder.py delete mode 100644 example/inertia-app/package.json delete mode 100644 example/inertia-app/providers/fastapi_provider.py delete mode 100644 example/inertia-app/pyproject.toml delete mode 100644 example/inertia-app/resources/css/app.css delete mode 100644 example/inertia-app/resources/js/Pages/Tickets.jsx delete mode 100644 example/inertia-app/resources/js/Pages/Welcome.jsx delete mode 100644 example/inertia-app/resources/js/app.jsx delete mode 100644 example/inertia-app/routes/web.py delete mode 100644 example/inertia-app/templates/index.html delete mode 100644 example/inertia-app/uv.lock delete mode 100644 example/inertia-app/vite.config.js diff --git a/example/inertia-app/.gitignore b/example/inertia-app/.gitignore deleted file mode 100644 index 53fdc66f..00000000 --- a/example/inertia-app/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -.venv -storage -node_modules -public/build -public/hot - -# Build outputs -dist/ -*.tsbuildinfo - -# Logs -*.log -npm-debug.log* diff --git a/example/inertia-app/app/models/Ticket.py b/example/inertia-app/app/models/Ticket.py deleted file mode 100644 index bd65bbdf..00000000 --- a/example/inertia-app/app/models/Ticket.py +++ /dev/null @@ -1,19 +0,0 @@ -from fastapi_startkit.masoniteorm.models import Model - - -class Ticket(Model): - __table__ = "tickets" - __primary_key__ = "id" - __timestamps__ = True - - id: int - title: str - team: str | None - status: str - from_name: str | None - assignee_id: int | None - preview: str | None - channel: str | None - customer_since: str | None - plan: str | None - monthly_sends: str | None diff --git a/example/inertia-app/artisan b/example/inertia-app/artisan deleted file mode 100644 index b998a2f3..00000000 --- a/example/inertia-app/artisan +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python3 - -import sys -from bootstrap.application import app - -if __name__ == "__main__": - status = app.handle_command() - sys.exit(status if isinstance(status, int) else 0) \ No newline at end of file diff --git a/example/inertia-app/bootstrap/application.py b/example/inertia-app/bootstrap/application.py deleted file mode 100644 index 0fbf778f..00000000 --- a/example/inertia-app/bootstrap/application.py +++ /dev/null @@ -1,20 +0,0 @@ -from pathlib import Path - -from fastapi_startkit import Application -from fastapi_startkit.logging import LogProvider -from fastapi_startkit.vite import ViteProvider -from fastapi_startkit.inertia import InertiaProvider -from fastapi_startkit.masoniteorm import DatabaseProvider - -from providers.fastapi_provider import FastAPIProvider - -app: Application = Application( - base_path=str(Path.cwd()), - providers=[ - LogProvider, - DatabaseProvider, - FastAPIProvider, - ViteProvider, - InertiaProvider, - ], -) diff --git a/example/inertia-app/config/database.py b/example/inertia-app/config/database.py deleted file mode 100644 index 9eec570e..00000000 --- a/example/inertia-app/config/database.py +++ /dev/null @@ -1,24 +0,0 @@ -from dataclasses import dataclass, field -from typing import Dict, Any - -from fastapi_startkit.environment import env -from fastapi_startkit.masoniteorm import SQLiteConfig - - -@dataclass -class DatabaseConfig: - default: str = field(default_factory=lambda: env("DB_CONNECTION", "pgsql")) - - connections: Dict[str, Dict[str, Any]] = field(default_factory=lambda: { - "sqlite": SQLiteConfig( - driver="sqlite", - database=env("DB_DATABASE", "database.sqlite"), - options=None, - ), - }) - - migrations: Dict[str, Dict[str, Any]] = field(default_factory=lambda: { - "table": "migrations", - - "path": "databases/migrations" - }) diff --git a/example/inertia-app/config/logging.py b/example/inertia-app/config/logging.py deleted file mode 100644 index 911606b6..00000000 --- a/example/inertia-app/config/logging.py +++ /dev/null @@ -1,23 +0,0 @@ -import dataclasses - -from fastapi_startkit.environment.environment import env -from fastapi_startkit.logging.config import DailyChannel, TerminalChannel, StackChannel - - -@dataclasses.dataclass -class LoggingConfig: - default: str = dataclasses.field(default_factory=lambda: env('LOG_CHANNEL', 'stack')) - - channels: dict = dataclasses.field(default_factory=lambda: { - 'stack': StackChannel( - driver='stack', - channels=['daily', 'terminal'] - ), - 'daily': DailyChannel( - level=env('LOG_DAILY_LEVEL', 'info'), - path=env('LOG_DAILY_PATH', 'storage/logs'), - ), - 'terminal': TerminalChannel( - level=env('LOG_TERMINAL_LEVEL', 'info'), - ), - }) diff --git a/example/inertia-app/databases/__init__.py b/example/inertia-app/databases/__init__.py deleted file mode 100644 index 789b4f0e..00000000 --- a/example/inertia-app/databases/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# databases package diff --git a/example/inertia-app/databases/factories/TicketFactory.py b/example/inertia-app/databases/factories/TicketFactory.py deleted file mode 100644 index 95cfd192..00000000 --- a/example/inertia-app/databases/factories/TicketFactory.py +++ /dev/null @@ -1,44 +0,0 @@ -from faker import Faker -import random - -fake = Faker() - -CHANNELS = ["email", "chat", "twitter", "phone", "web"] -PLANS = ["Free", "Starter", "Growth", "Enterprise"] -STATUSES = ["Open", "Waiting", "Closed", "Spam"] -TEAMS = ["Support", "Sales", "Billing", "Technical", "Onboarding"] - -PREVIEWS = [ - "Hey, I'm having trouble logging in to my account...", - "My payment failed and I need help resolving this immediately.", - "Could you help me understand how to export my data?", - "The dashboard is loading slowly since the last update.", - "I'd like to upgrade my plan, can you walk me through it?", - "There's an issue with the API returning 500 errors.", - "Can I get a refund for last month's subscription?", - "I accidentally deleted some important records, help!", - "How do I add team members to my workspace?", - "The email notifications stopped working for my account.", -] - - -def ticket_factory(overrides: dict = {}) -> dict: - """Return a dict of fake ticket attributes.""" - return { - "title": overrides.get("title", fake.sentence(nb_words=6).rstrip(".")), - "team": overrides.get("team", random.choice(TEAMS)), - "status": overrides.get("status", random.choice(STATUSES)), - "from_name": overrides.get("from_name", fake.name()), - "assignee_id": overrides.get("assignee_id", None), - "preview": overrides.get("preview", random.choice(PREVIEWS)), - "channel": overrides.get("channel", random.choice(CHANNELS)), - "customer_since": overrides.get("customer_since", fake.date(pattern="%B %Y")), - "plan": overrides.get("plan", random.choice(PLANS)), - "monthly_sends": overrides.get( - "monthly_sends", f"{random.randint(1, 500)}K" - ), - **{k: v for k, v in overrides.items() if k not in ( - "title", "team", "status", "from_name", "assignee_id", - "preview", "channel", "customer_since", "plan", "monthly_sends", - )}, - } diff --git a/example/inertia-app/databases/migrations/2026_04_21_000001_create_users_table.py b/example/inertia-app/databases/migrations/2026_04_21_000001_create_users_table.py deleted file mode 100644 index 2979eecb..00000000 --- a/example/inertia-app/databases/migrations/2026_04_21_000001_create_users_table.py +++ /dev/null @@ -1,22 +0,0 @@ -"""CreateUsersTable Migration.""" - -from fastapi_startkit.masoniteorm.migrations import Migration - - -class CreateUsersTable(Migration): - async def up(self): - """Run the migrations.""" - async with await self.schema.create("users") as table: - table.increments("id") - - table.string("name") - table.string("email").unique() - table.string("password") - table.string("avatar").nullable() # initials / avatar URL - table.string("remember_token", 100).nullable() - - table.timestamps() - - async def down(self): - """Revert the migrations.""" - await self.schema.drop("users") diff --git a/example/inertia-app/databases/migrations/2026_04_21_000002_create_tickets_table.py b/example/inertia-app/databases/migrations/2026_04_21_000002_create_tickets_table.py deleted file mode 100644 index 15731841..00000000 --- a/example/inertia-app/databases/migrations/2026_04_21_000002_create_tickets_table.py +++ /dev/null @@ -1,36 +0,0 @@ -"""CreateTicketsTable Migration.""" - -from fastapi_startkit.masoniteorm.migrations import Migration - - -class CreateTicketsTable(Migration): - async def up(self): - """Run the migrations.""" - async with await self.schema.create("tickets") as table: - table.increments("id") - - table.string("title") - table.string("team").nullable() - - # status: Open | Waiting | Closed | Spam - table.enum("status", ["Open", "Waiting", "Closed", "Spam"]).default("Open") - - # Sender / assignee - table.string("from_name").nullable() - table.unsigned_integer("assignee_id").nullable() - table.foreign("assignee_id").references("id").on("users").nullable() - - # Display metadata shown in the ticket list / detail - table.text("preview").nullable() - table.string("channel").nullable() - - # Customer info displayed in the meta-panel - table.string("customer_since").nullable() - table.string("plan").nullable() - table.string("monthly_sends").nullable() - - table.timestamps() - - async def down(self): - """Revert the migrations.""" - await self.schema.drop("tickets") diff --git a/example/inertia-app/databases/migrations/2026_04_21_000003_create_ticket_tags_table.py b/example/inertia-app/databases/migrations/2026_04_21_000003_create_ticket_tags_table.py deleted file mode 100644 index 00732c4f..00000000 --- a/example/inertia-app/databases/migrations/2026_04_21_000003_create_ticket_tags_table.py +++ /dev/null @@ -1,19 +0,0 @@ -"""CreateTicketTagsTable Migration.""" - -from fastapi_startkit.masoniteorm.migrations import Migration - - -class CreateTicketTagsTable(Migration): - async def up(self): - """Run the migrations.""" - async with await self.schema.create("ticket_tags") as table: - table.increments("id") - - table.unsigned_integer("ticket_id") - table.foreign("ticket_id").references("id").on("tickets").on_delete("cascade") - - table.string("tag") # e.g. Bug, Urgent, Question, Feature - - async def down(self): - """Revert the migrations.""" - await self.schema.drop("ticket_tags") diff --git a/example/inertia-app/databases/migrations/2026_04_21_000004_create_ticket_messages_table.py b/example/inertia-app/databases/migrations/2026_04_21_000004_create_ticket_messages_table.py deleted file mode 100644 index b152f3f2..00000000 --- a/example/inertia-app/databases/migrations/2026_04_21_000004_create_ticket_messages_table.py +++ /dev/null @@ -1,28 +0,0 @@ -"""CreateTicketMessagesTable Migration.""" - -from fastapi_startkit.masoniteorm.migrations import Migration - - -class CreateTicketMessagesTable(Migration): - async def up(self): - """Run the migrations.""" - async with await self.schema.create("ticket_messages") as table: - table.increments("id") - - table.unsigned_integer("ticket_id") - table.foreign("ticket_id").references("id").on("tickets").on_delete("cascade") - - # Can be a customer (no user account) or an agent (linked to users) - table.unsigned_integer("user_id").nullable() - table.foreign("user_id").references("id").on("users").nullable() - - table.string("author") # display name - table.string("avatar", 10).nullable() # initials, e.g. "FV" - table.text("body") - table.boolean("is_reply").default(False) # True = sent by an agent - - table.timestamps() - - async def down(self): - """Revert the migrations.""" - await self.schema.drop("ticket_messages") diff --git a/example/inertia-app/databases/migrations/__init__.py b/example/inertia-app/databases/migrations/__init__.py deleted file mode 100644 index 7f7d0d38..00000000 --- a/example/inertia-app/databases/migrations/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# migrations package diff --git a/example/inertia-app/databases/seeders/TicketSeeder.py b/example/inertia-app/databases/seeders/TicketSeeder.py deleted file mode 100644 index 81080e25..00000000 --- a/example/inertia-app/databases/seeders/TicketSeeder.py +++ /dev/null @@ -1,11 +0,0 @@ -from app.models.Ticket import Ticket -from databases.factories.TicketFactory import ticket_factory - - -class TicketSeeder: - async def run(self, count: int = 20): - """Seed the tickets table with fake data.""" - for _ in range(count): - await Ticket.create(ticket_factory()) - - print(f"Seeded {count} tickets.") diff --git a/example/inertia-app/databases/seeds/database_seeder.py b/example/inertia-app/databases/seeds/database_seeder.py deleted file mode 100644 index 06a911d9..00000000 --- a/example/inertia-app/databases/seeds/database_seeder.py +++ /dev/null @@ -1,6 +0,0 @@ -from databases.seeders.TicketSeeder import TicketSeeder - - -class DatabaseSeeder: - async def run(self): - await TicketSeeder(connection=self.connection).run() diff --git a/example/inertia-app/package.json b/example/inertia-app/package.json deleted file mode 100644 index 6c4168e2..00000000 --- a/example/inertia-app/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "inertia-app", - "private": true, - "type": "module", - "version": "0.1.0", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "dependencies": { - "@inertiajs/react": "^3.0.0", - "fastapi-vite-plugin": "^0.0.3", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "vite-plugin-full-reload": "^1.2.0" - }, - "devDependencies": { - "@inertiajs/vite": "^3.0.0", - "@tailwindcss/vite": "^4.2.4", - "@types/node": "^25.6.0", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.0.0", - "vite": "^8.0.0" - } -} diff --git a/example/inertia-app/providers/fastapi_provider.py b/example/inertia-app/providers/fastapi_provider.py deleted file mode 100644 index 91286b01..00000000 --- a/example/inertia-app/providers/fastapi_provider.py +++ /dev/null @@ -1,30 +0,0 @@ -from pathlib import Path - -from fastapi import FastAPI -from starlette.templating import Jinja2Templates - -from fastapi_startkit.fastapi.providers import FastAPIProvider as BaseFastAPIProvider - - -class FastAPIProvider(BaseFastAPIProvider): - def register(self) -> None: - fastapi = FastAPI( - title="Vite Example", - version="0.1.0", - ) - self.app.use_fastapi(fastapi) - - # Bind Jinja2Templates so ViteProvider can inject vite() globals into it. - templates_dir = Path(self.app.base_path) / "templates" - templates = Jinja2Templates(directory=str(templates_dir)) - self.app.bind("templates", templates) - - def boot(self) -> None: - super().boot() - - inertia = self.app.make("inertia") - inertia.share("app_name", "Inertia Demo") - inertia.version("v1.0.0") - - from routes.web import web - self.app.include_router(web) \ No newline at end of file diff --git a/example/inertia-app/pyproject.toml b/example/inertia-app/pyproject.toml deleted file mode 100644 index 1b863096..00000000 --- a/example/inertia-app/pyproject.toml +++ /dev/null @@ -1,18 +0,0 @@ -[project] -name = "inertia-example" -version = "0.1.0" -description = "Vite + FastAPI example using fastapi-startkit" -requires-python = ">=3.12" -dependencies = [ - "faker>=40.15.0", - "fastapi-startkit[fastapi,database,postgres]", - "jinja2>=3.1", -] - -[tool.uv.sources] -fastapi-startkit = { path = "../../fastapi_startkit", editable = true } - -[dependency-groups] -dev = [ - "dumpdie>=1.5.0", -] diff --git a/example/inertia-app/resources/css/app.css b/example/inertia-app/resources/css/app.css deleted file mode 100644 index a461c505..00000000 --- a/example/inertia-app/resources/css/app.css +++ /dev/null @@ -1 +0,0 @@ -@import "tailwindcss"; \ No newline at end of file diff --git a/example/inertia-app/resources/js/Pages/Tickets.jsx b/example/inertia-app/resources/js/Pages/Tickets.jsx deleted file mode 100644 index 4c8cc1a2..00000000 --- a/example/inertia-app/resources/js/Pages/Tickets.jsx +++ /dev/null @@ -1,460 +0,0 @@ -import { useState } from 'react' - -// ─── Mock Data ──────────────────────────────────────────────────────────────── - -const TEAMS = [ - { id: 1, name: 'Flare', color: '#f97316', count: 54 }, - { id: 2, name: 'Mailcoach', color: '#8b5cf6', count: 49 }, - { id: 3, name: 'Ray', color: '#06b6d4', count: 10 }, -] - -const NAV_MINE = [ - { id: 'open', label: 'My open tickets', count: 26, icon: '📬' }, - { id: 'waiting', label: 'My waiting tickets', count: 0, icon: '⏳' }, - { id: 'closed', label: 'My closed tickets', count: 18, icon: '✅' }, -] - -const NAV_WORKSPACE = [ - { id: 'ws-open', label: 'Open', count: 204 }, - { id: 'ws-waiting', label: 'Waiting', count: 27 }, - { id: 'ws-closed', label: 'Closed', count: 175 }, - { id: 'ws-spam', label: 'Spam', count: 0 }, - { id: 'ws-assigned', label: 'Assigned', count: 151 }, - { id: 'ws-all', label: 'All', count: 406 }, -] - -const TICKETS = [ - { - id: 405, - title: 'Large CSV subscriber import silently failing at ~12k rows', - team: 'Mailcoach Support', - status: 'Open', - statusColor: 'green', - from: 'Elena Vasquez', - to: 'Freek Van der Herten', - tags: ['Bug'], - time: '21m ago', - preview: 'Elena reports 45k subscriber CSV import only importing ~12k rows with no errors shown. Caused by Redis memory exhaustion during chunked import processing.', - assignee: { name: 'Freek Van der Herten', avatar: 'FV' }, - channel: 'Mailcoach Support', - customerSince: 'Jan 12, 2024', - plan: 'Business (annual)', - monthlySends: '187,420', - messages: [ - { id: 1, author: 'Elena Vasquez', avatar: 'EV', time: '59m ago', body: 'Hi there, We\'re trying to import a CSV with about 45,000 subscribers but only ~12k are being imported. There are no errors shown anywhere. Can you help?' }, - { id: 2, author: 'Freek Van der Herten', avatar: 'FV', time: '41m ago', body: 'Hi Elena, This is a known issue with large imports when Redis memory is constrained. Fixed by reducing import_chunk_size to 1000 in mailcoach.php config.', isReply: true }, - { id: 3, author: 'Elena Vasquez', avatar: 'EV', time: '31m ago', body: 'Freek, That worked perfectly! All 45,247 subscribers imported successfully. Thank you so much!' }, - ], - }, - { - id: 404, - title: 'Tag changes not reflecting on subscribers', - team: 'Mailcoach Support', - status: 'Open', - statusColor: 'green', - from: 'Myron Kohler', - to: 'Freek Van der Herten', - tags: ['Bug', 'Question'], - time: '21m ago', - preview: 'User reports subscriber tags not updating or syncing correctly.', - assignee: { name: 'Freek Van der Herten', avatar: 'FV' }, - channel: 'Mailcoach Support', - customerSince: 'Mar 5, 2023', - plan: 'Starter (monthly)', - monthlySends: '12,300', - messages: [ - { id: 1, author: 'Myron Kohler', avatar: 'MK', time: '21m ago', body: 'Tags I assign to subscribers in the UI don\'t seem to stick. After refreshing they\'re gone.' }, - ], - }, - { - id: 381, - title: 'Ray consuming too much memory', - team: 'Spatie support', - status: 'Open', - statusColor: 'green', - from: 'Helmer Zboncak', - to: 'Freek Van der Herten', - tags: ['Urgent'], - time: '3h ago', - preview: 'User concerned about Ray\'s memory usage with large datasets in long-running processes.', - assignee: { name: 'Freek Van der Herten', avatar: 'FV' }, - channel: 'Spatie Support', - customerSince: 'Jun 18, 2022', - plan: 'Enterprise', - monthlySends: '—', - messages: [ - { id: 1, author: 'Helmer Zboncak', avatar: 'HZ', time: '3h ago', body: 'Ray seems to keep all dump data in memory during long-running artisan commands. After a few hours our process OOM crashes.' }, - ], - }, - { - id: 379, - title: 'Webhook delivery retries not working after 24h', - team: 'Flare', - status: 'Waiting', - statusColor: 'yellow', - from: 'Casimir Tromp', - to: 'Ruben Van Assche', - tags: ['Bug'], - time: '5h ago', - preview: 'Webhook events are not retried after the first 24 hour window expires, even though retry policy is set.', - assignee: { name: 'Ruben Van Assche', avatar: 'RV' }, - channel: 'Flare', - customerSince: 'Sep 2, 2021', - plan: 'Business (annual)', - monthlySends: '—', - messages: [ - { id: 1, author: 'Casimir Tromp', avatar: 'CT', time: '5h ago', body: 'Our webhook retry policy is set to retry for 72 hours but after 24h all retries stop.' }, - ], - }, - { - id: 377, - title: 'Cannot set reply-to address per campaign', - team: 'Mailcoach Support', - status: 'Closed', - statusColor: 'slate', - from: 'Petra Morar', - to: 'Freek Van der Herten', - tags: ['Question'], - time: '1d ago', - preview: 'User asking how to configure a different reply-to address for individual campaigns.', - assignee: { name: 'Freek Van der Herten', avatar: 'FV' }, - channel: 'Mailcoach Support', - customerSince: 'Feb 14, 2023', - plan: 'Business (annual)', - monthlySends: '58,100', - messages: [ - { id: 1, author: 'Petra Morar', avatar: 'PM', time: '1d ago', body: 'Is it possible to set a different reply-to for each campaign individually?' }, - { id: 2, author: 'Freek Van der Herten', avatar: 'FV', time: '23h ago', body: 'Yes! In the campaign settings under "From & Reply-to" you can override the default per campaign.', isReply: true }, - ], - }, -] - -// ─── Sub-components ─────────────────────────────────────────────────────────── - -const TAG_COLORS = { - Bug: 'bg-red-500/20 text-red-300 border-red-500/30', - Urgent: 'bg-orange-500/20 text-orange-300 border-orange-500/30', - Question: 'bg-blue-500/20 text-blue-300 border-blue-500/30', - Feature: 'bg-green-500/20 text-green-300 border-green-500/30', -} - -const STATUS_COLORS = { - Open: 'bg-emerald-400', - Waiting: 'bg-yellow-400', - Closed: 'bg-slate-500', -} - -function Avatar({ initials, size = 'sm', color }) { - const colors = { - FV: 'bg-purple-600', EV: 'bg-pink-600', MK: 'bg-blue-600', - HZ: 'bg-orange-600', RV: 'bg-cyan-600', CT: 'bg-rose-600', - PM: 'bg-teal-600', - } - const sz = size === 'sm' ? 'w-7 h-7 text-xs' : 'w-9 h-9 text-sm' - return ( -
- {initials} -
- ) -} - -function Tag({ label }) { - return ( - - {label} - - ) -} - -// ─── Sidebar ───────────────────────────────────────────────────────────────── - -function Sidebar({ activeNav, setActiveNav, selectedTicket }) { - return ( - - ) -} - -// ─── Ticket List ────────────────────────────────────────────────────────────── - -function TicketList({ tickets, selectedId, onSelect }) { - return ( -
- {/* Header */} -
-
- - Filters -
-
- - {/* Ticket rows */} -
- {tickets.map(ticket => ( - - ))} -
-
- ) -} - -// ─── Ticket Detail ──────────────────────────────────────────────────────────── - -function TicketDetail({ ticket }) { - const [reply, setReply] = useState('') - - if (!ticket) { - return ( -
-
-
💬
-

Select a ticket to view it

-
-
- ) - } - - return ( -
- {/* Ticket header */} -
-
-
-
- {ticket.status} - · - #{ticket.id} -
-

{ticket.title}

-
- -
- - {/* Messages */} -
- {ticket.messages.map(msg => ( -
- -
-
- {msg.author} - {msg.isReply && Reply} - {msg.time} -
-
- {msg.body} -
-
-
- ))} -
- - {/* Reply box */} -
-
-