saveinmed/frontend/docs/codigo_completo.md

672 KiB
Raw Blame History

Código-fonte Completo

Esta referência lista todos os arquivos do projeto SaveInMed Frontend com seus respectivos conteúdos. Utilize o sumário abaixo para navegar.

Última atualização: 2025-07-15

Sumário

Visão Geral da Arquitetura

O projeto utiliza o Next.js com App Router e rotas de API rodando em Edge Runtime. Os serviços se comunicam com o Appwrite para persistência de dados.

Usuário -> Página/Hook -> Service -> (API Route?) -> Appwrite

Os hooks são responsáveis por orquestrar estado e chamadas ao serviço, mantendo a UI reativa.

Padrões Utilizados

  • Services centralizam o acesso às coleções do Appwrite.
  • Hooks provêm funções listar, criar, atualizar e deletar e mantêm estados de loading.
  • Componentes seguem o estilo descrito em CODEX_STYLE_GUIDE.md.

Exemplo de Uso do Hook

import { useLaboratorios } from '@/hooks/useLaboratorios';

const { laboratorios, listarLaboratorios } = useLaboratorios();

useEffect(() => {
  listarLaboratorios();
}, []);

Rotas de API

As rotas seguem o padrão REST e são definidas em src/app/api. Cada coleção possui dois arquivos: route.ts para operações em lote e [id]/route.ts para ações em um item específico. Todas elas executam em Edge Runtime e utilizam a API Key configurada no servidor.

Hooks Customizados

Os hooks localizados em src/hooks encapsulam a comunicação com os serviços e expõem estados de loading e erro. Utilize-os dentro dos componentes para lidar com dados de maneira reativa.

.env.example

# Endpoint da API do Appwrite
NEXT_PUBLIC_APPWRITE_ENDPOINT=https://seu-endpoint.appwrite.io/v1

# ID do projeto Appwrite
NEXT_PUBLIC_APPWRITE_PROJECT_ID=your-project-id

# ID do banco de dados do Appwrite
NEXT_PUBLIC_APPWRITE_DATABASE_ID=your-database-id

# IDs das coleções
NEXT_PUBLIC_APPWRITE_COLLECTION_ENDERECOS_ID=your-enderecos-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_LABORATORIOS_ID=your-laboratorios-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_EMPRESAS_ID=your-empresas-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_USUARIOS_ID=your-usuarios-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_CATEGORIAS_ID=your-categorias-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_FATURAS_ID=your-faturas-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_PAGAMENTOS_ID=your-pagamentos-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_PRODUTOS_ID=your-produtos-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_CARRINHOS_ID=your-carrinhos-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_CATALOGO_PRODUTOS_ID=your-catalogo-produtos-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_PEDIDOS_ID=your-pedidos-collection-id

# API Key usada nas API Routes (somente no servidor)
APPWRITE_API_KEY=chave-secreta

# ID da Function "caju" do Appwrite
NEXT_PUBLIC_APPWRITE_FUNCTION_CAJU_ID=


.gitignore

# 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*
!*.example

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts


README-old.md

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 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 to automatically optimize and load Geist, a new font family for Vercel.

Learn More

To learn more about Next.js, take a look at the following resources:

You can check out the Next.js GitHub repository - your feedback and contributions are welcome!

Deploy on Vercel

The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.

Check out our Next.js deployment documentation for more details.


---

### README.md
```markdown
# SaveInMed Frontend

## Visão Geral do Projeto

Aplicação **Next.js** que serve como interface da plataforma B2B SaveInMed, permitindo farmácias comprarem e venderem medicamentos próximos ao vencimento. O projeto inclui páginas de login, dashboard e rotas de API para cadastro e gerenciamento de empresas.

### Tecnologias Utilizadas

- [Next.js](https://nextjs.org/) 15 com TypeScript
- React 19
- Tailwind CSS
- ESLint
- [Appwrite](https://appwrite.io/) para autenticação e banco de dados

### Principais Funcionalidades

- Autenticação de usuários (login e registro)
- Dashboard com estatísticas e ações rápidas
- CRUD de empresas via API Routes
- Integração com Appwrite (Account e Databases)

## Estrutura de Pastas

src/ app/ # Páginas e rotas (App Router) components/ # Componentes reutilizáveis lib/ # Configurações e serviços externos public/ # Imagens e arquivos estáticos


### Principais Arquivos

- `next.config.ts`  Configurações do Next.js
- `postcss.config.mjs`  Plugins do PostCSS/Tailwind
- `eslint.config.mjs`  Regras do ESLint
- `.env.example`  Exemplo de variáveis de ambiente
- `package.json`  Scripts e dependências

## Instalação e Setup

### Requisitos

- Node.js 18 ou superior
- npm 9+ (ou yarn/pnpm)

### Passo a Passo

1. Instale as dependências:
   ```bash
   npm install
  1. Copie o arquivo .env.example para .env e ajuste os valores.
  2. Rode em modo desenvolvimento:
    npm run dev
    
  3. Para gerar o build de produção:
    npm run build
    npm start
    

Deploy

O projeto pode ser implantado em plataformas compatíveis com aplicações Next.js (Vercel, Netlify, etc.).

Ambientes

Exemplo de .env:

# Endpoint da API do Appwrite
NEXT_PUBLIC_APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
# ID do projeto Appwrite
NEXT_PUBLIC_APPWRITE_PROJECT_ID=your-project-id
# ID do banco de dados
NEXT_PUBLIC_APPWRITE_DATABASE_ID=your-database-id
# IDs das coleções
NEXT_PUBLIC_APPWRITE_COLLECTION_ENDERECOS_ID=your-enderecos-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_LABORATORIOS_ID=your-laboratorios-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_EMPRESAS_ID=your-empresas-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_USUARIOS_ID=your-usuarios-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_CATEGORIAS_ID=your-categorias-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_FATURAS_ID=your-faturas-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_PAGAMENTOS_ID=your-pagamentos-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_PRODUTOS_ID=your-produtos-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_CARRINHOS_ID=your-carrinhos-collection-id
NEXT_PUBLIC_APPWRITE_COLLECTION_CATALOGO_PRODUTOS_ID=your-catalogo-produtos-collection-id
# API Key usada nas rotas de API (somente servidor)
APPWRITE_API_KEY=your-appwrite-api-key

Nunca suba seu arquivo .env para o Git.

Variáveis Obrigatórias

  • NEXT_PUBLIC_APPWRITE_ENDPOINT
  • NEXT_PUBLIC_APPWRITE_PROJECT_ID
  • NEXT_PUBLIC_APPWRITE_DATABASE_ID
  • NEXT_PUBLIC_APPWRITE_COLLECTION_ENDERECOS_ID
  • NEXT_PUBLIC_APPWRITE_COLLECTION_LABORATORIOS_ID
  • NEXT_PUBLIC_APPWRITE_COLLECTION_EMPRESAS_ID
  • NEXT_PUBLIC_APPWRITE_COLLECTION_USUARIOS_ID
  • NEXT_PUBLIC_APPWRITE_COLLECTION_CATEGORIAS_ID
  • NEXT_PUBLIC_APPWRITE_COLLECTION_FATURAS_ID
  • NEXT_PUBLIC_APPWRITE_COLLECTION_PAGAMENTOS_ID
  • NEXT_PUBLIC_APPWRITE_COLLECTION_PRODUTOS_ID
  • NEXT_PUBLIC_APPWRITE_COLLECTION_CARRINHOS_ID
  • NEXT_PUBLIC_APPWRITE_COLLECTION_CATALOGO_PRODUTOS_ID
  • APPWRITE_API_KEY (somente nas rotas de API)

Scripts npm

  • dev Inicia o servidor de desenvolvimento
  • build Gera o build de produção
  • start Executa o build
  • lint Analisa o código com ESLint

Configurações Especiais

  • Tailwind: configurado via postcss.config.mjs e importado em globals.css.
  • ESLint: regras em eslint.config.mjs seguindo next/core-web-vitals.

Integrações Externas

  • Appwrite utilizado para autenticação e banco de dados. A configuração está em src/lib/appwrite.ts.

Rotas Principais

Frontend

  • / Página de login/registro
  • /dashboard Dashboard principal
  • /dashboard/empresa-novo Gestão de empresas

API Routes

  • /api/empresas Listar e cadastrar empresas
  • /api/empresas/[id] Atualizar e excluir empresa
  • /api/user/permissions Verificar permissões do usuário

Componentes Importantes

  • Header e Navbar em src/components
  • Outros componentes específicos dentro das páginas

Exemplos de Uso

Consumindo API interna

const response = await fetch('/api/empresas');
const data = await response.json();

Utilizando componente compartilhado

import Header from '@/components/Header';

<Header user={user} />

Esquemas de Coleção

Paginação com Appwrite

As rotas de API utilizam a REST API do Appwrite. Para que o Appwrite retorne o total e os documentos corretos é necessário enviar os parâmetros limit e offset dentro de queries[].

/v1/databases/{databaseId}/collections/{collectionId}/documents?queries[]=limit(10)&queries[]=offset(10)

As páginas do frontend passam page e limit para as rotas de API, que traduzem esses valores para o formato acima.

Boas Práticas

  • Utilize nomes descritivos para pastas e arquivos.
  • Novos componentes devem ficar em src/components.
  • Novas rotas de página em src/app/<rota>.
  • Lógica de backend deve ser colocada em src/app/api/*.

Fluxo de Deploy

  1. Defina as variáveis de ambiente no ambiente de produção.
  2. Execute npm run build e faça o deploy da pasta .next (em plataformas como Vercel o processo é automático).

Observações Finais

Sinta-se à vontade para contribuir com o projeto através de issues e pull requests.

Créditos

Projeto baseado no boilerplate do Next.js com adaptações para uso de Appwrite.

ToDo Futuro

  • Melhorar testes e cobertura de código
  • Adicionar mais componentes reutilizáveis

---

### docs/CODEX_STYLE_GUIDE.md
```markdown
# Blueprint de CRUD com Appwrite

Este documento padroniza a criação de novas features baseadas em CRUD no projeto. Todas as adições de código **devem** seguir o arquivo `CODEX_STYLE_GUIDE.md` e a estrutura demonstrada abaixo.

## Estrutura Básica

src/ app// # páginas e formulários app/api// # rotas de API (Edge Runtime) components/ # componentes reutilizáveis hooks/ # hooks de consumo services/ # serviços com Appwrite


### Fluxo de listagem e cadastro
As listagens (GET) costumam usar diretamente o SDK do Appwrite dentro do
`<feature>Service`, como acontece em `laboratorioService.ts`. Já as operações de
criação, atualização e exclusão são enviadas para rotas de API do Next.js para
que a `APPWRITE_API_KEY` fique somente no servidor.

Arquivos envolvidos no exemplo de **Laboratorios**:

- `src/services/laboratorioService.ts`  usa `databases.listDocuments` para
  listar e chama `/api/laboratorios` nas operações de escrita.
- `src/app/api/laboratorios/route.ts`  implementa GET e POST.
- `src/app/api/laboratorios/[id]/route.ts`  implementa PATCH e DELETE.

Ao criar uma nova feature, siga o mesmo padrão substituindo os nomes e adicione
a variável `NEXT_PUBLIC_APPWRITE_COLLECTION_<FEATURE>_ID` no `.env.example`.

## 1. Service
Arquivo: `src/services/<feature>Service.ts`

```ts
import { databases, ID, Query } from '@/lib/appwrite';

const DB_ID  = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
const COL_ID = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_<FEATURE>_ID!;
const LIMIT  = 10;

export interface <Feature>Data {
  // campos da collection
}

class <Feature>Service {
  async listar(page = 1, search = '') {
    const offset  = (page - 1) * LIMIT;
    const queries = [
      Query.limit(LIMIT),
      Query.offset(offset),
      ...(search ? [Query.search('nome', search)] : [])
    ];
    return databases.listDocuments(DB_ID, COL_ID, queries);
  }

  criar(data: <Feature>Data) {
    return databases.createDocument(DB_ID, COL_ID, ID.unique(), data);
  }

  atualizar(id: string, data: <Feature>Data) {
    return databases.updateDocument(DB_ID, COL_ID, id, data);
  }

  deletar(id: string) {
    return databases.deleteDocument(DB_ID, COL_ID, id);
  }
}

export const <feature>Service = new <Feature>Service();

Substitua <feature> e <Feature> pelo nome real.

2. Hook

Arquivo: src/hooks/use<FeaturePlural>.ts

import { useState, useCallback } from 'react';
import { Models } from 'appwrite';
import { <feature>Service, <Feature>Data } from '@/services/<feature>Service';

export const PAGE_SIZE = 10;

export const use<FeaturePlural> = () => {
  const [itens, setItens]   = useState<Models.Document[]>([]);
  const [loading, setLoad ] = useState(false);
  const [error, setError ]  = useState<string | null>(null);
  const [total, setTotal ]  = useState(0);
  const [page,  setPage  ]  = useState(1);

  const fetch = useCallback(async (p = page, term = '') => {
    setLoad(true);
    try {
      const res = await <feature>Service.listar(p, term);
      setItens(res.documents);
      setTotal(res.total);
      setPage(p);
      setError(null);
    } catch (err: any) {
      setError(err.message ?? 'Erro ao listar');
    } finally {
      setLoad(false);
    }
  }, [page]);

  return {
    itens, loading, error, total, page, fetch,
    criar:    (d: <Feature>Data)              => <feature>Service.criar(d),
    atualizar:(id: string, d: <Feature>Data ) => <feature>Service.atualizar(id, d),
    deletar:  (id: string)                  => <feature>Service.deletar(id),
  };
};

3. Componentes

Formulário

Arquivo: src/components/<Feature>Form.tsx

import React, { useState, useEffect } from 'react';
import { <Feature>Data } from '@/services/<feature>Service';

type Props = {
  onSubmit: (d: <Feature>Data) => Promise<void>;
  onCancel?: () => void;
  initialData?: <Feature>Data | null;
  loading?: boolean;
};

const <Feature>Form: React.FC<Props> = ({
  onSubmit, onCancel, initialData, loading = false
}) => {
  const [data, setData] = useState<<Feature>Data>({
    // campos iniciais
  });

  useEffect(() => initialData && setData(initialData), [initialData]);

  const handle = (e: React.FormEvent) => {
    e.preventDefault();
    onSubmit(data);
  };

  return (
    <form onSubmit={handle} className="space-y-4 p-4">
      {/* inputs */}
      <div className="flex gap-2">
        <button disabled={loading} className="btn-primary flex-1">Salvar</button>
        {onCancel &&
          <button type="button" onClick={onCancel} className="btn-secondary flex-1">
            Cancelar
          </button>}
      </div>
    </form>
  );
};

export default <Feature>Form;

Lista

Arquivo: src/components/<Feature>List.tsx

import React from 'react';
import { Models } from 'appwrite';
import SearchBar from '@/components/SearchBar';
import RefreshButton from '@/components/RefreshButton';
import ListHeader from '@/components/ListHeader';
import DataTable, { Column } from '@/components/DataTable';
import Pagination from '@/components/Pagination';

type Props = {
  itens: Models.Document[];
  loading: boolean;
  page: number;
  total: number;
  onEdit:   (doc: Models.Document) => void;
  onDelete: (id: string) => void;
  onPrev: () => void;
  onNext: () => void;
  onSearch: (term: string) => void;
  onRefresh: () => void;
};

const columns: Column<Models.Document>[] = [
  { key: 'nome', header: 'Nome' },
  { key: '$id', header: 'ID' },
];

const <Feature>List: React.FC<Props> = ({
  itens, loading, page, total, onEdit, onDelete, onPrev, onNext, onSearch, onRefresh
}) => {
  const [search, setSearch] = React.useState('');

  return (
    <div className="space-y-2">
      <ListHeader title="<FeaturePlural>">
        <SearchBar
          value={search}
          onChange={setSearch}
          onSearch={() => onSearch(search)}
          placeholder="Buscar nome"
        />
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      <DataTable
        columns={columns}
        data={itens}
        actions={(row) => (
          <>
            <button onClick={() => onEdit(row)}>Editar</button>
            <button onClick={() => onDelete(row.$id)}>Deletar</button>
          </>
        )}
      />

      <Pagination page={page} total={Math.ceil(total / 10) || 1} onPrev={onPrev} onNext={onNext} />
    </div>
  );
};

export default <Feature>List;

Padrões Visuais de Listagens

As listagens usam o estilo aplicado em LaboratorioList como referência para todo o sistema:

  • Container: container mx-auto px-4 py-8.
  • Cabeçalho: componente ListHeader com título text-gray-800 font-bold text-2xl e área de ações com flex items-center gap-2.
  • Barra de busca: SearchBar possui input com px-3 py-2 border border-gray-300 rounded-md text-gray-900 bg-white placeholder-gray-500 e botão bg-blue-600 text-white h-10 px-4 rounded-md.
  • Botão de atualizar: RefreshButton segue o mesmo padrão de cores do botão de busca (bg-blue-600 text-white h-10 px-4 rounded-md).
  • Tabela: DataTable contém bg-white shadow-md rounded-lg overflow-hidden border border-gray-200 e cabeçalho bg-gray-50.
  • Linhas: alternância odd:bg-gray-50 e hover hover:bg-gray-100 com bordas border-gray-200.
  • Ações: botões gerados por ActionButton usando variantes (edit, delete, view) com rounded-md px-2 py-1 text-xs.
  • Paginação: Pagination utiliza botões px-3 py-1 text-sm border border-gray-300 rounded-md bg-white text-gray-700 hover:bg-gray-50.

Este mesmo layout é utilizado em CatalogoProdutosList para manter a consistência visual entre os módulos.

Padrões Visuais de Formulários

Os formulários seguem o estilo de LaboratorioForm:

  • Container: bg-white rounded-lg shadow-md p-6.
  • Cabeçalho: título text-2xl font-bold text-gray-900 mb-2 e descrição text-gray-600.
  • Campos: inputs w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed text-gray-900 bg-white placeholder:text-gray-500.
  • Layout: grupos separados por space-y-6 e botões dentro de flex gap-4.
  • Botões: principal bg-blue-600 text-white h-10 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed e secundário bg-gray-600 text-white h-10 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed.

4. Página

Arquivo: src/app/<feature>/page.tsx

'use client';
import React, { useEffect, useState } from 'react';
import { use<FeaturePlural> } from '@/hooks/use<FeaturePlural>';
import <Feature>Form from '@/components/<Feature>Form';
import <Feature>List from '@/components/<Feature>List';

export default function <FeaturePlural>Page() {
  const {
    itens, loading, error, total, page,
    fetch, criar, atualizar, deletar
  } = use<FeaturePlural>();

  const [editDoc, setEditDoc] = useState<any | null>(null);

  useEffect(() => { fetch(); }, []);

  const handleSave = async (data: any) => {
    editDoc ? await atualizar(editDoc.$id, data) : await criar(data);
    setEditDoc(null);
    fetch();
  };

  return (
    <main className="p-6 space-y-4">
      <h1 className="text-xl font-semibold"><FeaturePlural></h1>

      <<Feature>Form
        initialData={editDoc}
        onSubmit={handleSave}
        onCancel={() => setEditDoc(null)}
      />

      {error && <p className="text-red-600">{error}</p>}

      <<Feature>List
        itens={itens}
        loading={loading}
        total={total}
        page={page}
        onEdit={setEditDoc}
        onDelete={async id => { await deletar(id); fetch(); }}
        onPrev={() => fetch(page - 1)}
        onNext={() => fetch(page + 1)}
      />
    </main>
  );
}

5. API Routes

src/app/api/<feature>/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { databases, Query, ID } from '@/lib/appwrite';

export const runtime = 'edge';

const DB  = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
const COL = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_<FEATURE>_ID!;
const LIMIT = 10;

export async function GET(req: NextRequest) {
  const search = req.nextUrl.searchParams.get('q') ?? '';
  const page   = +(req.nextUrl.searchParams.get('page') ?? 1);
  const queries = [
    Query.limit(LIMIT),
    Query.offset((page - 1) * LIMIT),
    ...(search ? [Query.search('nome', search)] : [])
  ];
  const data = await databases.listDocuments(DB, COL, queries);
  return NextResponse.json({ success: true, ...data });
}

export async function POST(req: NextRequest) {
  const body = await req.json();
  const doc = await databases.createDocument(DB, COL, ID.unique(), body);
  return NextResponse.json({ success: true, data: doc }, { status: 201 });
}

src/app/api/<feature>/[id]/route.ts

import { NextRequest, NextResponse, unstable_rootParams } from 'next/server';
import { databases } from '@/lib/appwrite';

export const runtime = 'edge';

const DB  = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
const COL = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_<FEATURE>_ID!;

export async function PATCH(req: NextRequest) {
  const { id } = await unstable_rootParams();
  const body   = await req.json();
  const doc = await databases.updateDocument(DB, COL, id, body);
  return NextResponse.json({ success: true, data: doc });
}

export async function DELETE() {
  const { id } = await unstable_rootParams();
  await databases.deleteDocument(DB, COL, id);
  return NextResponse.json({ success: true });
}

Siga este blueprint ao criar novas funcionalidades. Renomeie corretamente <feature> e <Feature> e ajuste os campos de dados conforme a coleção do Appwrite.


---

### docs/collections/catalogo-produtos.md
```markdown
# Estrutura da Coleção `catalogo-produtos`

Este documento apresenta a organização sugerida para a coleção `catalogo-produtos`,
seguindo o padrão das coleções **laboratorio** e **carrinho**.

## Campos

| Chave                          | Tipo   | Grupo            |
|--------------------------------|--------|------------------|
| codigo_interno                 | String | Dados do produto |
| codigo_ean                     | String | Dados do produto |
| descricao                      | String | Dados do produto |
| preco_fabrica                  | Double | Preços e valores |
| pmc                            | Double | Preços e valores |
| desconto_comercial             | Double | Preços e valores |
| valor_substituicao_tributaria  | Double | Preços e valores |
| preco_nf                       | Double | Preços e valores |
| laboratorio                    | Relacionamento | Relacionamentos |
| subcategoria                   | Relacionamento | Relacionamentos |
| categoria                      | Relacionamento | Relacionamentos |

## Organização visual

Crie grupos de atributos no painel do Appwrite na seguinte ordem:

1. **Dados do produto**  códigos e descrição
2. **Preços e valores**  todos os valores monetários
3. **Relacionamentos**  laboratórios e categorias

Cada grupo deve apresentar os campos listados na tabela acima,
respeitando a disposição vertical utilizada em `laboratorio` e `carrinho`.

## Relacionamentos

Os campos `laboratorio`, `subcategoria` e `categoria` devem ser
relacionados às respectivas coleções. A interface deve exibir um dropdown
com o nome do item enquanto o ID permanece oculto, imitando o
funcionamento do formulário de **carrinho**.

## Validações e padrões

- Campos numéricos não devem aceitar valores negativos.
- `desconto_comercial` pode ter valor padrão `0`.
- Todos os campos são obrigatórios, inclusive as relações.

Com estas configurações a coleção `catalogo-produtos` ficará consistente
com as demais coleções do projeto.



eslint.config.mjs

import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const compat = new FlatCompat({
  baseDirectory: __dirname,
});

const eslintConfig = [
  ...compat.extends("next/core-web-vitals", "next/typescript"),
  {
    rules: {
      "@typescript-eslint/no-explicit-any": "off",
      "@typescript-eslint/no-unused-vars": "off",
      "@typescript-eslint/no-empty-object-type": "off",
      "@typescript-eslint/ban-ts-comment": "off",
      "react/no-unescaped-entities": "off",
      "react-hooks/exhaustive-deps": "off",
    },
  },
];

export default eslintConfig;


next-env.d.ts

/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.


next.config.ts

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
};

export default nextConfig;


package-lock.json

{
  "name": "frontend",
  "version": "0.1.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "frontend",
      "version": "0.1.0",
      "dependencies": {
        "appwrite": "^18.1.1",
        "next": "15.3.4",
        "node-appwrite": "^17.0.0",
        "react": "^19.0.0",
        "react-dom": "^19.0.0"
      },
      "devDependencies": {
        "@eslint/eslintrc": "^3",
        "@tailwindcss/postcss": "^4",
        "@types/node": "^20",
        "@types/react": "^19",
        "@types/react-dom": "^19",
        "eslint": "^9",
        "eslint-config-next": "15.3.4",
        "tailwindcss": "^4",
        "typescript": "^5"
      }
    },
    "node_modules/@alloc/quick-lru": {
      "version": "5.2.0",
      "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
      "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/@ampproject/remapping": {
      "version": "2.3.0",
      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
      "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
      "dev": true,
      "license": "Apache-2.0",
      "dependencies": {
        "@jridgewell/gen-mapping": "^0.3.5",
        "@jridgewell/trace-mapping": "^0.3.24"
      },
      "engines": {
        "node": ">=6.0.0"
      }
    },
    "node_modules/@emnapi/core": {
      "version": "1.4.3",
      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz",
      "integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==",
      "dev": true,
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "@emnapi/wasi-threads": "1.0.2",
        "tslib": "^2.4.0"
      }
    },
    "node_modules/@emnapi/runtime": {
      "version": "1.4.3",
      "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz",
      "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==",
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "tslib": "^2.4.0"
      }
    },
    "node_modules/@emnapi/wasi-threads": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz",
      "integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==",
      "dev": true,
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "tslib": "^2.4.0"
      }
    },
    "node_modules/@eslint-community/eslint-utils": {
      "version": "4.7.0",
      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
      "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "eslint-visitor-keys": "^3.4.3"
      },
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint"
      },
      "peerDependencies": {
        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
      }
    },
    "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
      "version": "3.4.3",
      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
      "dev": true,
      "license": "Apache-2.0",
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint"
      }
    },
    "node_modules/@eslint-community/regexpp": {
      "version": "4.12.1",
      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
      "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
      }
    },
    "node_modules/@eslint/config-array": {
      "version": "0.20.1",
      "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
      "integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
      "dev": true,
      "license": "Apache-2.0",
      "dependencies": {
        "@eslint/object-schema": "^2.1.6",
        "debug": "^4.3.1",
        "minimatch": "^3.1.2"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      }
    },
    "node_modules/@eslint/config-helpers": {
      "version": "0.2.3",
      "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.3.tgz",
      "integrity": "sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==",
      "dev": true,
      "license": "Apache-2.0",
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      }
    },
    "node_modules/@eslint/core": {
      "version": "0.14.0",
      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz",
      "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==",
      "dev": true,
      "license": "Apache-2.0",
      "dependencies": {
        "@types/json-schema": "^7.0.15"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      }
    },
    "node_modules/@eslint/eslintrc": {
      "version": "3.3.1",
      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
      "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "ajv": "^6.12.4",
        "debug": "^4.3.2",
        "espree": "^10.0.1",
        "globals": "^14.0.0",
        "ignore": "^5.2.0",
        "import-fresh": "^3.2.1",
        "js-yaml": "^4.1.0",
        "minimatch": "^3.1.2",
        "strip-json-comments": "^3.1.1"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint"
      }
    },
    "node_modules/@eslint/js": {
      "version": "9.29.0",
      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
      "integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "url": "https://eslint.org/donate"
      }
    },
    "node_modules/@eslint/object-schema": {
      "version": "2.1.6",
      "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
      "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
      "dev": true,
      "license": "Apache-2.0",
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      }
    },
    "node_modules/@eslint/plugin-kit": {
      "version": "0.3.2",
      "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.2.tgz",
      "integrity": "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg==",
      "dev": true,
      "license": "Apache-2.0",
      "dependencies": {
        "@eslint/core": "^0.15.0",
        "levn": "^0.4.1"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      }
    },
    "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
      "version": "0.15.0",
      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.0.tgz",
      "integrity": "sha512-b7ePw78tEWWkpgZCDYkbqDOP8dmM6qe+AOC6iuJqlq1R/0ahMAeH3qynpnqKFGkMltrp44ohV4ubGyvLX28tzw==",
      "dev": true,
      "license": "Apache-2.0",
      "dependencies": {
        "@types/json-schema": "^7.0.15"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      }
    },
    "node_modules/@humanfs/core": {
      "version": "0.19.1",
      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
      "dev": true,
      "license": "Apache-2.0",
      "engines": {
        "node": ">=18.18.0"
      }
    },
    "node_modules/@humanfs/node": {
      "version": "0.16.6",
      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
      "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
      "dev": true,
      "license": "Apache-2.0",
      "dependencies": {
        "@humanfs/core": "^0.19.1",
        "@humanwhocodes/retry": "^0.3.0"
      },
      "engines": {
        "node": ">=18.18.0"
      }
    },
    "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": {
      "version": "0.3.1",
      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
      "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
      "dev": true,
      "license": "Apache-2.0",
      "engines": {
        "node": ">=18.18"
      },
      "funding": {
        "type": "github",
        "url": "https://github.com/sponsors/nzakas"
      }
    },
    "node_modules/@humanwhocodes/module-importer": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
      "dev": true,
      "license": "Apache-2.0",
      "engines": {
        "node": ">=12.22"
      },
      "funding": {
        "type": "github",
        "url": "https://github.com/sponsors/nzakas"
      }
    },
    "node_modules/@humanwhocodes/retry": {
      "version": "0.4.3",
      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
      "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
      "dev": true,
      "license": "Apache-2.0",
      "engines": {
        "node": ">=18.18"
      },
      "funding": {
        "type": "github",
        "url": "https://github.com/sponsors/nzakas"
      }
    },
    "node_modules/@img/sharp-darwin-arm64": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz",
      "integrity": "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==",
      "cpu": [
        "arm64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      },
      "optionalDependencies": {
        "@img/sharp-libvips-darwin-arm64": "1.1.0"
      }
    },
    "node_modules/@img/sharp-darwin-x64": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.2.tgz",
      "integrity": "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==",
      "cpu": [
        "x64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      },
      "optionalDependencies": {
        "@img/sharp-libvips-darwin-x64": "1.1.0"
      }
    },
    "node_modules/@img/sharp-libvips-darwin-arm64": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz",
      "integrity": "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==",
      "cpu": [
        "arm64"
      ],
      "license": "LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "darwin"
      ],
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-libvips-darwin-x64": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz",
      "integrity": "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==",
      "cpu": [
        "x64"
      ],
      "license": "LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "darwin"
      ],
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-libvips-linux-arm": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz",
      "integrity": "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==",
      "cpu": [
        "arm"
      ],
      "license": "LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "linux"
      ],
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-libvips-linux-arm64": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz",
      "integrity": "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==",
      "cpu": [
        "arm64"
      ],
      "license": "LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "linux"
      ],
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-libvips-linux-ppc64": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz",
      "integrity": "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==",
      "cpu": [
        "ppc64"
      ],
      "license": "LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "linux"
      ],
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-libvips-linux-s390x": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz",
      "integrity": "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==",
      "cpu": [
        "s390x"
      ],
      "license": "LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "linux"
      ],
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-libvips-linux-x64": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz",
      "integrity": "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==",
      "cpu": [
        "x64"
      ],
      "license": "LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "linux"
      ],
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz",
      "integrity": "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==",
      "cpu": [
        "arm64"
      ],
      "license": "LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "linux"
      ],
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-libvips-linuxmusl-x64": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz",
      "integrity": "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==",
      "cpu": [
        "x64"
      ],
      "license": "LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "linux"
      ],
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-linux-arm": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.2.tgz",
      "integrity": "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==",
      "cpu": [
        "arm"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      },
      "optionalDependencies": {
        "@img/sharp-libvips-linux-arm": "1.1.0"
      }
    },
    "node_modules/@img/sharp-linux-arm64": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.2.tgz",
      "integrity": "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==",
      "cpu": [
        "arm64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      },
      "optionalDependencies": {
        "@img/sharp-libvips-linux-arm64": "1.1.0"
      }
    },
    "node_modules/@img/sharp-linux-s390x": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.2.tgz",
      "integrity": "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==",
      "cpu": [
        "s390x"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      },
      "optionalDependencies": {
        "@img/sharp-libvips-linux-s390x": "1.1.0"
      }
    },
    "node_modules/@img/sharp-linux-x64": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.2.tgz",
      "integrity": "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==",
      "cpu": [
        "x64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      },
      "optionalDependencies": {
        "@img/sharp-libvips-linux-x64": "1.1.0"
      }
    },
    "node_modules/@img/sharp-linuxmusl-arm64": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.2.tgz",
      "integrity": "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==",
      "cpu": [
        "arm64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      },
      "optionalDependencies": {
        "@img/sharp-libvips-linuxmusl-arm64": "1.1.0"
      }
    },
    "node_modules/@img/sharp-linuxmusl-x64": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.2.tgz",
      "integrity": "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==",
      "cpu": [
        "x64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      },
      "optionalDependencies": {
        "@img/sharp-libvips-linuxmusl-x64": "1.1.0"
      }
    },
    "node_modules/@img/sharp-wasm32": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.2.tgz",
      "integrity": "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==",
      "cpu": [
        "wasm32"
      ],
      "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
      "optional": true,
      "dependencies": {
        "@emnapi/runtime": "^1.4.3"
      },
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-win32-arm64": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.2.tgz",
      "integrity": "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ==",
      "cpu": [
        "arm64"
      ],
      "license": "Apache-2.0 AND LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-win32-ia32": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.2.tgz",
      "integrity": "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==",
      "cpu": [
        "ia32"
      ],
      "license": "Apache-2.0 AND LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@img/sharp-win32-x64": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.2.tgz",
      "integrity": "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==",
      "cpu": [
        "x64"
      ],
      "license": "Apache-2.0 AND LGPL-3.0-or-later",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      }
    },
    "node_modules/@isaacs/fs-minipass": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
      "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
      "dev": true,
      "license": "ISC",
      "dependencies": {
        "minipass": "^7.0.4"
      },
      "engines": {
        "node": ">=18.0.0"
      }
    },
    "node_modules/@jridgewell/gen-mapping": {
      "version": "0.3.8",
      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
      "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@jridgewell/set-array": "^1.2.1",
        "@jridgewell/sourcemap-codec": "^1.4.10",
        "@jridgewell/trace-mapping": "^0.3.24"
      },
      "engines": {
        "node": ">=6.0.0"
      }
    },
    "node_modules/@jridgewell/resolve-uri": {
      "version": "3.1.2",
      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=6.0.0"
      }
    },
    "node_modules/@jridgewell/set-array": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
      "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=6.0.0"
      }
    },
    "node_modules/@jridgewell/sourcemap-codec": {
      "version": "1.5.0",
      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
      "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/@jridgewell/trace-mapping": {
      "version": "0.3.25",
      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
      "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@jridgewell/resolve-uri": "^3.1.0",
        "@jridgewell/sourcemap-codec": "^1.4.14"
      }
    },
    "node_modules/@napi-rs/wasm-runtime": {
      "version": "0.2.11",
      "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz",
      "integrity": "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==",
      "dev": true,
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "@emnapi/core": "^1.4.3",
        "@emnapi/runtime": "^1.4.3",
        "@tybys/wasm-util": "^0.9.0"
      }
    },
    "node_modules/@next/env": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.4.tgz",
      "integrity": "sha512-ZkdYzBseS6UjYzz6ylVKPOK+//zLWvD6Ta+vpoye8cW11AjiQjGYVibF0xuvT4L0iJfAPfZLFidaEzAOywyOAQ==",
      "license": "MIT"
    },
    "node_modules/@next/eslint-plugin-next": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.3.4.tgz",
      "integrity": "sha512-lBxYdj7TI8phbJcLSAqDt57nIcobEign5NYIKCiy0hXQhrUbTqLqOaSDi568U6vFg4hJfBdZYsG4iP/uKhCqgg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "fast-glob": "3.3.1"
      }
    },
    "node_modules/@next/swc-darwin-arm64": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.4.tgz",
      "integrity": "sha512-z0qIYTONmPRbwHWvpyrFXJd5F9YWLCsw3Sjrzj2ZvMYy9NPQMPZ1NjOJh4ojr4oQzcGYwgJKfidzehaNa1BpEg==",
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@next/swc-darwin-x64": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.4.tgz",
      "integrity": "sha512-Z0FYJM8lritw5Wq+vpHYuCIzIlEMjewG2aRkc3Hi2rcbULknYL/xqfpBL23jQnCSrDUGAo/AEv0Z+s2bff9Zkw==",
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@next/swc-linux-arm64-gnu": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.4.tgz",
      "integrity": "sha512-l8ZQOCCg7adwmsnFm8m5q9eIPAHdaB2F3cxhufYtVo84pymwKuWfpYTKcUiFcutJdp9xGHC+F1Uq3xnFU1B/7g==",
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@next/swc-linux-arm64-musl": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.4.tgz",
      "integrity": "sha512-wFyZ7X470YJQtpKot4xCY3gpdn8lE9nTlldG07/kJYexCUpX1piX+MBfZdvulo+t1yADFVEuzFfVHfklfEx8kw==",
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@next/swc-linux-x64-gnu": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.4.tgz",
      "integrity": "sha512-gEbH9rv9o7I12qPyvZNVTyP/PWKqOp8clvnoYZQiX800KkqsaJZuOXkWgMa7ANCCh/oEN2ZQheh3yH8/kWPSEg==",
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@next/swc-linux-x64-musl": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.4.tgz",
      "integrity": "sha512-Cf8sr0ufuC/nu/yQ76AnarbSAXcwG/wj+1xFPNbyNo8ltA6kw5d5YqO8kQuwVIxk13SBdtgXrNyom3ZosHAy4A==",
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@next/swc-win32-arm64-msvc": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.4.tgz",
      "integrity": "sha512-ay5+qADDN3rwRbRpEhTOreOn1OyJIXS60tg9WMYTWCy3fB6rGoyjLVxc4dR9PYjEdR2iDYsaF5h03NA+XuYPQQ==",
      "cpu": [
        "arm64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@next/swc-win32-x64-msvc": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.4.tgz",
      "integrity": "sha512-4kDt31Bc9DGyYs41FTL1/kNpDeHyha2TC0j5sRRoKCyrhNcfZ/nRQkAUlF27mETwm8QyHqIjHJitfcza2Iykfg==",
      "cpu": [
        "x64"
      ],
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@nodelib/fs.scandir": {
      "version": "2.1.5",
      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@nodelib/fs.stat": "2.0.5",
        "run-parallel": "^1.1.9"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/@nodelib/fs.stat": {
      "version": "2.0.5",
      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/@nodelib/fs.walk": {
      "version": "1.2.8",
      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@nodelib/fs.scandir": "2.1.5",
        "fastq": "^1.6.0"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/@nolyfill/is-core-module": {
      "version": "1.0.39",
      "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz",
      "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=12.4.0"
      }
    },
    "node_modules/@rtsao/scc": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
      "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/@rushstack/eslint-patch": {
      "version": "1.11.0",
      "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.11.0.tgz",
      "integrity": "sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/@swc/counter": {
      "version": "0.1.3",
      "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
      "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
      "license": "Apache-2.0"
    },
    "node_modules/@swc/helpers": {
      "version": "0.5.15",
      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
      "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
      "license": "Apache-2.0",
      "dependencies": {
        "tslib": "^2.8.0"
      }
    },
    "node_modules/@tailwindcss/node": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.10.tgz",
      "integrity": "sha512-2ACf1znY5fpRBwRhMgj9ZXvb2XZW8qs+oTfotJ2C5xR0/WNL7UHZ7zXl6s+rUqedL1mNi+0O+WQr5awGowS3PQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@ampproject/remapping": "^2.3.0",
        "enhanced-resolve": "^5.18.1",
        "jiti": "^2.4.2",
        "lightningcss": "1.30.1",
        "magic-string": "^0.30.17",
        "source-map-js": "^1.2.1",
        "tailwindcss": "4.1.10"
      }
    },
    "node_modules/@tailwindcss/oxide": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.10.tgz",
      "integrity": "sha512-v0C43s7Pjw+B9w21htrQwuFObSkio2aV/qPx/mhrRldbqxbWJK6KizM+q7BF1/1CmuLqZqX3CeYF7s7P9fbA8Q==",
      "dev": true,
      "hasInstallScript": true,
      "license": "MIT",
      "dependencies": {
        "detect-libc": "^2.0.4",
        "tar": "^7.4.3"
      },
      "engines": {
        "node": ">= 10"
      },
      "optionalDependencies": {
        "@tailwindcss/oxide-android-arm64": "4.1.10",
        "@tailwindcss/oxide-darwin-arm64": "4.1.10",
        "@tailwindcss/oxide-darwin-x64": "4.1.10",
        "@tailwindcss/oxide-freebsd-x64": "4.1.10",
        "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.10",
        "@tailwindcss/oxide-linux-arm64-gnu": "4.1.10",
        "@tailwindcss/oxide-linux-arm64-musl": "4.1.10",
        "@tailwindcss/oxide-linux-x64-gnu": "4.1.10",
        "@tailwindcss/oxide-linux-x64-musl": "4.1.10",
        "@tailwindcss/oxide-wasm32-wasi": "4.1.10",
        "@tailwindcss/oxide-win32-arm64-msvc": "4.1.10",
        "@tailwindcss/oxide-win32-x64-msvc": "4.1.10"
      }
    },
    "node_modules/@tailwindcss/oxide-android-arm64": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.10.tgz",
      "integrity": "sha512-VGLazCoRQ7rtsCzThaI1UyDu/XRYVyH4/EWiaSX6tFglE+xZB5cvtC5Omt0OQ+FfiIVP98su16jDVHDEIuH4iQ==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "android"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@tailwindcss/oxide-darwin-arm64": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.10.tgz",
      "integrity": "sha512-ZIFqvR1irX2yNjWJzKCqTCcHZbgkSkSkZKbRM3BPzhDL/18idA8uWCoopYA2CSDdSGFlDAxYdU2yBHwAwx8euQ==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@tailwindcss/oxide-darwin-x64": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.10.tgz",
      "integrity": "sha512-eCA4zbIhWUFDXoamNztmS0MjXHSEJYlvATzWnRiTqJkcUteSjO94PoRHJy1Xbwp9bptjeIxxBHh+zBWFhttbrQ==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@tailwindcss/oxide-freebsd-x64": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.10.tgz",
      "integrity": "sha512-8/392Xu12R0cc93DpiJvNpJ4wYVSiciUlkiOHOSOQNH3adq9Gi/dtySK7dVQjXIOzlpSHjeCL89RUUI8/GTI6g==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "freebsd"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.10.tgz",
      "integrity": "sha512-t9rhmLT6EqeuPT+MXhWhlRYIMSfh5LZ6kBrC4FS6/+M1yXwfCtp24UumgCWOAJVyjQwG+lYva6wWZxrfvB+NhQ==",
      "cpu": [
        "arm"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.10.tgz",
      "integrity": "sha512-3oWrlNlxLRxXejQ8zImzrVLuZ/9Z2SeKoLhtCu0hpo38hTO2iL86eFOu4sVR8cZc6n3z7eRXXqtHJECa6mFOvA==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.10.tgz",
      "integrity": "sha512-saScU0cmWvg/Ez4gUmQWr9pvY9Kssxt+Xenfx1LG7LmqjcrvBnw4r9VjkFcqmbBb7GCBwYNcZi9X3/oMda9sqQ==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.10.tgz",
      "integrity": "sha512-/G3ao/ybV9YEEgAXeEg28dyH6gs1QG8tvdN9c2MNZdUXYBaIY/Gx0N6RlJzfLy/7Nkdok4kaxKPHKJUlAaoTdA==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@tailwindcss/oxide-linux-x64-musl": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.10.tgz",
      "integrity": "sha512-LNr7X8fTiKGRtQGOerSayc2pWJp/9ptRYAa4G+U+cjw9kJZvkopav1AQc5HHD+U364f71tZv6XamaHKgrIoVzA==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@tailwindcss/oxide-wasm32-wasi": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.10.tgz",
      "integrity": "sha512-d6ekQpopFQJAcIK2i7ZzWOYGZ+A6NzzvQ3ozBvWFdeyqfOZdYHU66g5yr+/HC4ipP1ZgWsqa80+ISNILk+ae/Q==",
      "bundleDependencies": [
        "@napi-rs/wasm-runtime",
        "@emnapi/core",
        "@emnapi/runtime",
        "@tybys/wasm-util",
        "@emnapi/wasi-threads",
        "tslib"
      ],
      "cpu": [
        "wasm32"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "@emnapi/core": "^1.4.3",
        "@emnapi/runtime": "^1.4.3",
        "@emnapi/wasi-threads": "^1.0.2",
        "@napi-rs/wasm-runtime": "^0.2.10",
        "@tybys/wasm-util": "^0.9.0",
        "tslib": "^2.8.0"
      },
      "engines": {
        "node": ">=14.0.0"
      }
    },
    "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.10.tgz",
      "integrity": "sha512-i1Iwg9gRbwNVOCYmnigWCCgow8nDWSFmeTUU5nbNx3rqbe4p0kRbEqLwLJbYZKmSSp23g4N6rCDmm7OuPBXhDA==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.10.tgz",
      "integrity": "sha512-sGiJTjcBSfGq2DVRtaSljq5ZgZS2SDHSIfhOylkBvHVjwOsodBhnb3HdmiKkVuUGKD0I7G63abMOVaskj1KpOA==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">= 10"
      }
    },
    "node_modules/@tailwindcss/postcss": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.10.tgz",
      "integrity": "sha512-B+7r7ABZbkXJwpvt2VMnS6ujcDoR2OOcFaqrLIo1xbcdxje4Vf+VgJdBzNNbrAjBj/rLZ66/tlQ1knIGNLKOBQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@alloc/quick-lru": "^5.2.0",
        "@tailwindcss/node": "4.1.10",
        "@tailwindcss/oxide": "4.1.10",
        "postcss": "^8.4.41",
        "tailwindcss": "4.1.10"
      }
    },
    "node_modules/@tybys/wasm-util": {
      "version": "0.9.0",
      "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz",
      "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==",
      "dev": true,
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "tslib": "^2.4.0"
      }
    },
    "node_modules/@types/estree": {
      "version": "1.0.8",
      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
      "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/@types/json-schema": {
      "version": "7.0.15",
      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/@types/json5": {
      "version": "0.0.29",
      "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
      "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/@types/node": {
      "version": "20.19.1",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.1.tgz",
      "integrity": "sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "undici-types": "~6.21.0"
      }
    },
    "node_modules/@types/react": {
      "version": "19.1.8",
      "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz",
      "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "csstype": "^3.0.2"
      }
    },
    "node_modules/@types/react-dom": {
      "version": "19.1.6",
      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz",
      "integrity": "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==",
      "dev": true,
      "license": "MIT",
      "peerDependencies": {
        "@types/react": "^19.0.0"
      }
    },
    "node_modules/@typescript-eslint/eslint-plugin": {
      "version": "8.34.1",
      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
      "integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@eslint-community/regexpp": "^4.10.0",
        "@typescript-eslint/scope-manager": "8.34.1",
        "@typescript-eslint/type-utils": "8.34.1",
        "@typescript-eslint/utils": "8.34.1",
        "@typescript-eslint/visitor-keys": "8.34.1",
        "graphemer": "^1.4.0",
        "ignore": "^7.0.0",
        "natural-compare": "^1.4.0",
        "ts-api-utils": "^2.1.0"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/typescript-eslint"
      },
      "peerDependencies": {
        "@typescript-eslint/parser": "^8.34.1",
        "eslint": "^8.57.0 || ^9.0.0",
        "typescript": ">=4.8.4 <5.9.0"
      }
    },
    "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
      "version": "7.0.5",
      "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
      "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 4"
      }
    },
    "node_modules/@typescript-eslint/parser": {
      "version": "8.34.1",
      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz",
      "integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@typescript-eslint/scope-manager": "8.34.1",
        "@typescript-eslint/types": "8.34.1",
        "@typescript-eslint/typescript-estree": "8.34.1",
        "@typescript-eslint/visitor-keys": "8.34.1",
        "debug": "^4.3.4"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/typescript-eslint"
      },
      "peerDependencies": {
        "eslint": "^8.57.0 || ^9.0.0",
        "typescript": ">=4.8.4 <5.9.0"
      }
    },
    "node_modules/@typescript-eslint/project-service": {
      "version": "8.34.1",
      "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
      "integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@typescript-eslint/tsconfig-utils": "^8.34.1",
        "@typescript-eslint/types": "^8.34.1",
        "debug": "^4.3.4"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/typescript-eslint"
      },
      "peerDependencies": {
        "typescript": ">=4.8.4 <5.9.0"
      }
    },
    "node_modules/@typescript-eslint/scope-manager": {
      "version": "8.34.1",
      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
      "integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@typescript-eslint/types": "8.34.1",
        "@typescript-eslint/visitor-keys": "8.34.1"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/typescript-eslint"
      }
    },
    "node_modules/@typescript-eslint/tsconfig-utils": {
      "version": "8.34.1",
      "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
      "integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/typescript-eslint"
      },
      "peerDependencies": {
        "typescript": ">=4.8.4 <5.9.0"
      }
    },
    "node_modules/@typescript-eslint/type-utils": {
      "version": "8.34.1",
      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
      "integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@typescript-eslint/typescript-estree": "8.34.1",
        "@typescript-eslint/utils": "8.34.1",
        "debug": "^4.3.4",
        "ts-api-utils": "^2.1.0"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/typescript-eslint"
      },
      "peerDependencies": {
        "eslint": "^8.57.0 || ^9.0.0",
        "typescript": ">=4.8.4 <5.9.0"
      }
    },
    "node_modules/@typescript-eslint/types": {
      "version": "8.34.1",
      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz",
      "integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/typescript-eslint"
      }
    },
    "node_modules/@typescript-eslint/typescript-estree": {
      "version": "8.34.1",
      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
      "integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@typescript-eslint/project-service": "8.34.1",
        "@typescript-eslint/tsconfig-utils": "8.34.1",
        "@typescript-eslint/types": "8.34.1",
        "@typescript-eslint/visitor-keys": "8.34.1",
        "debug": "^4.3.4",
        "fast-glob": "^3.3.2",
        "is-glob": "^4.0.3",
        "minimatch": "^9.0.4",
        "semver": "^7.6.0",
        "ts-api-utils": "^2.1.0"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/typescript-eslint"
      },
      "peerDependencies": {
        "typescript": ">=4.8.4 <5.9.0"
      }
    },
    "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
      "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "balanced-match": "^1.0.0"
      }
    },
    "node_modules/@typescript-eslint/typescript-estree/node_modules/fast-glob": {
      "version": "3.3.3",
      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
      "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@nodelib/fs.stat": "^2.0.2",
        "@nodelib/fs.walk": "^1.2.3",
        "glob-parent": "^5.1.2",
        "merge2": "^1.3.0",
        "micromatch": "^4.0.8"
      },
      "engines": {
        "node": ">=8.6.0"
      }
    },
    "node_modules/@typescript-eslint/typescript-estree/node_modules/glob-parent": {
      "version": "5.1.2",
      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
      "dev": true,
      "license": "ISC",
      "dependencies": {
        "is-glob": "^4.0.1"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
      "version": "9.0.5",
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
      "dev": true,
      "license": "ISC",
      "dependencies": {
        "brace-expansion": "^2.0.1"
      },
      "engines": {
        "node": ">=16 || 14 >=14.17"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
    "node_modules/@typescript-eslint/utils": {
      "version": "8.34.1",
      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.1.tgz",
      "integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@eslint-community/eslint-utils": "^4.7.0",
        "@typescript-eslint/scope-manager": "8.34.1",
        "@typescript-eslint/types": "8.34.1",
        "@typescript-eslint/typescript-estree": "8.34.1"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/typescript-eslint"
      },
      "peerDependencies": {
        "eslint": "^8.57.0 || ^9.0.0",
        "typescript": ">=4.8.4 <5.9.0"
      }
    },
    "node_modules/@typescript-eslint/visitor-keys": {
      "version": "8.34.1",
      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
      "integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@typescript-eslint/types": "8.34.1",
        "eslint-visitor-keys": "^4.2.1"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/typescript-eslint"
      }
    },
    "node_modules/@unrs/resolver-binding-android-arm-eabi": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.9.0.tgz",
      "integrity": "sha512-h1T2c2Di49ekF2TE8ZCoJkb+jwETKUIPDJ/nO3tJBKlLFPu+fyd93f0rGP/BvArKx2k2HlRM4kqkNarj3dvZlg==",
      "cpu": [
        "arm"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "android"
      ]
    },
    "node_modules/@unrs/resolver-binding-android-arm64": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.9.0.tgz",
      "integrity": "sha512-sG1NHtgXtX8owEkJ11yn34vt0Xqzi3k9TJ8zppDmyG8GZV4kVWw44FHwKwHeEFl07uKPeC4ZoyuQaGh5ruJYPA==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "android"
      ]
    },
    "node_modules/@unrs/resolver-binding-darwin-arm64": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.9.0.tgz",
      "integrity": "sha512-nJ9z47kfFnCxN1z/oYZS7HSNsFh43y2asePzTEZpEvK7kGyuShSl3RRXnm/1QaqFL+iP+BjMwuB+DYUymOkA5A==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ]
    },
    "node_modules/@unrs/resolver-binding-darwin-x64": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.9.0.tgz",
      "integrity": "sha512-TK+UA1TTa0qS53rjWn7cVlEKVGz2B6JYe0C++TdQjvWYIyx83ruwh0wd4LRxYBM5HeuAzXcylA9BH2trARXJTw==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ]
    },
    "node_modules/@unrs/resolver-binding-freebsd-x64": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.9.0.tgz",
      "integrity": "sha512-6uZwzMRFcD7CcCd0vz3Hp+9qIL2jseE/bx3ZjaLwn8t714nYGwiE84WpaMCYjU+IQET8Vu/+BNAGtYD7BG/0yA==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "freebsd"
      ]
    },
    "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.9.0.tgz",
      "integrity": "sha512-bPUBksQfrgcfv2+mm+AZinaKq8LCFvt5PThYqRotqSuuZK1TVKkhbVMS/jvSRfYl7jr3AoZLYbDkItxgqMKRkg==",
      "cpu": [
        "arm"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.9.0.tgz",
      "integrity": "sha512-uT6E7UBIrTdCsFQ+y0tQd3g5oudmrS/hds5pbU3h4s2t/1vsGWbbSKhBSCD9mcqaqkBwoqlECpUrRJCmldl8PA==",
      "cpu": [
        "arm"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.9.0.tgz",
      "integrity": "sha512-vdqBh911wc5awE2bX2zx3eflbyv8U9xbE/jVKAm425eRoOVv/VseGZsqi3A3SykckSpF4wSROkbQPvbQFn8EsA==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@unrs/resolver-binding-linux-arm64-musl": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.9.0.tgz",
      "integrity": "sha512-/8JFZ/SnuDr1lLEVsxsuVwrsGquTvT51RZGvyDB/dOK3oYK2UqeXzgeyq6Otp8FZXQcEYqJwxb9v+gtdXn03eQ==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.9.0.tgz",
      "integrity": "sha512-FkJjybtrl+rajTw4loI3L6YqSOpeZfDls4SstL/5lsP2bka9TiHUjgMBjygeZEis1oC8LfJTS8FSgpKPaQx2tQ==",
      "cpu": [
        "ppc64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.9.0.tgz",
      "integrity": "sha512-w/NZfHNeDusbqSZ8r/hp8iL4S39h4+vQMc9/vvzuIKMWKppyUGKm3IST0Qv0aOZ1rzIbl9SrDeIqK86ZpUK37w==",
      "cpu": [
        "riscv64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.9.0.tgz",
      "integrity": "sha512-bEPBosut8/8KQbUixPry8zg/fOzVOWyvwzOfz0C0Rw6dp+wIBseyiHKjkcSyZKv/98edrbMknBaMNJfA/UEdqw==",
      "cpu": [
        "riscv64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.9.0.tgz",
      "integrity": "sha512-LDtMT7moE3gK753gG4pc31AAqGUC86j3AplaFusc717EUGF9ZFJ356sdQzzZzkBk1XzMdxFyZ4f/i35NKM/lFA==",
      "cpu": [
        "s390x"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@unrs/resolver-binding-linux-x64-gnu": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.9.0.tgz",
      "integrity": "sha512-WmFd5KINHIXj8o1mPaT8QRjA9HgSXhN1gl9Da4IZihARihEnOylu4co7i/yeaIpcfsI6sYs33cNZKyHYDh0lrA==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@unrs/resolver-binding-linux-x64-musl": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.9.0.tgz",
      "integrity": "sha512-CYuXbANW+WgzVRIl8/QvZmDaZxrqvOldOwlbUjIM4pQ46FJ0W5cinJ/Ghwa/Ng1ZPMJMk1VFdsD/XwmCGIXBWg==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@unrs/resolver-binding-wasm32-wasi": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.9.0.tgz",
      "integrity": "sha512-6Rp2WH0OoitMYR57Z6VE8Y6corX8C6QEMWLgOV6qXiJIeZ1F9WGXY/yQ8yDC4iTraotyLOeJ2Asea0urWj2fKQ==",
      "cpu": [
        "wasm32"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "@napi-rs/wasm-runtime": "^0.2.11"
      },
      "engines": {
        "node": ">=14.0.0"
      }
    },
    "node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.9.0.tgz",
      "integrity": "sha512-rknkrTRuvujprrbPmGeHi8wYWxmNVlBoNW8+4XF2hXUnASOjmuC9FNF1tGbDiRQWn264q9U/oGtixyO3BT8adQ==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ]
    },
    "node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.9.0.tgz",
      "integrity": "sha512-Ceymm+iBl+bgAICtgiHyMLz6hjxmLJKqBim8tDzpX61wpZOx2bPK6Gjuor7I2RiUynVjvvkoRIkrPyMwzBzF3A==",
      "cpu": [
        "ia32"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ]
    },
    "node_modules/@unrs/resolver-binding-win32-x64-msvc": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.9.0.tgz",
      "integrity": "sha512-k59o9ZyeyS0hAlcaKFezYSH2agQeRFEB7KoQLXl3Nb3rgkqT1NY9Vwy+SqODiLmYnEjxWJVRE/yq2jFVqdIxZw==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ]
    },
    "node_modules/acorn": {
      "version": "8.15.0",
      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
      "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
      "dev": true,
      "license": "MIT",
      "bin": {
        "acorn": "bin/acorn"
      },
      "engines": {
        "node": ">=0.4.0"
      }
    },
    "node_modules/acorn-jsx": {
      "version": "5.3.2",
      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
      "dev": true,
      "license": "MIT",
      "peerDependencies": {
        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
      }
    },
    "node_modules/ajv": {
      "version": "6.12.6",
      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "fast-deep-equal": "^3.1.1",
        "fast-json-stable-stringify": "^2.0.0",
        "json-schema-traverse": "^0.4.1",
        "uri-js": "^4.2.2"
      },
      "funding": {
        "type": "github",
        "url": "https://github.com/sponsors/epoberezkin"
      }
    },
    "node_modules/ansi-styles": {
      "version": "4.3.0",
      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "color-convert": "^2.0.1"
      },
      "engines": {
        "node": ">=8"
      },
      "funding": {
        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
      }
    },
    "node_modules/appwrite": {
      "version": "18.1.1",
      "resolved": "https://registry.npmjs.org/appwrite/-/appwrite-18.1.1.tgz",
      "integrity": "sha512-krwHjuwJcF+9Ig2+nqOEKMA/5kPIFhwwZsaLc7Gb8y2oP6EnG4ZMRPeHTFscdevOtVQj2Ax92cYYWAEvzlrc7A==",
      "license": "BSD-3-Clause"
    },
    "node_modules/argparse": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
      "dev": true,
      "license": "Python-2.0"
    },
    "node_modules/aria-query": {
      "version": "5.3.2",
      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
      "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
      "dev": true,
      "license": "Apache-2.0",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/array-buffer-byte-length": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
      "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3",
        "is-array-buffer": "^3.0.5"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/array-includes": {
      "version": "3.1.9",
      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
      "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.4",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.24.0",
        "es-object-atoms": "^1.1.1",
        "get-intrinsic": "^1.3.0",
        "is-string": "^1.1.1",
        "math-intrinsics": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/array.prototype.findlast": {
      "version": "1.2.5",
      "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
      "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.7",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.2",
        "es-errors": "^1.3.0",
        "es-object-atoms": "^1.0.0",
        "es-shim-unscopables": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/array.prototype.findlastindex": {
      "version": "1.2.6",
      "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
      "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.4",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.9",
        "es-errors": "^1.3.0",
        "es-object-atoms": "^1.1.1",
        "es-shim-unscopables": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/array.prototype.flat": {
      "version": "1.3.3",
      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
      "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.5",
        "es-shim-unscopables": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/array.prototype.flatmap": {
      "version": "1.3.3",
      "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
      "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.5",
        "es-shim-unscopables": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/array.prototype.tosorted": {
      "version": "1.1.4",
      "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
      "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.7",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.3",
        "es-errors": "^1.3.0",
        "es-shim-unscopables": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/arraybuffer.prototype.slice": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
      "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "array-buffer-byte-length": "^1.0.1",
        "call-bind": "^1.0.8",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.5",
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.6",
        "is-array-buffer": "^3.0.4"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/ast-types-flow": {
      "version": "0.0.8",
      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
      "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/async-function": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
      "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/available-typed-arrays": {
      "version": "1.0.7",
      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
      "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "possible-typed-array-names": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/axe-core": {
      "version": "4.10.3",
      "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz",
      "integrity": "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==",
      "dev": true,
      "license": "MPL-2.0",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/axobject-query": {
      "version": "4.1.0",
      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
      "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
      "dev": true,
      "license": "Apache-2.0",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/balanced-match": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/brace-expansion": {
      "version": "1.1.12",
      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "balanced-match": "^1.0.0",
        "concat-map": "0.0.1"
      }
    },
    "node_modules/braces": {
      "version": "3.0.3",
      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "fill-range": "^7.1.1"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/busboy": {
      "version": "1.6.0",
      "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
      "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
      "dependencies": {
        "streamsearch": "^1.1.0"
      },
      "engines": {
        "node": ">=10.16.0"
      }
    },
    "node_modules/call-bind": {
      "version": "1.0.8",
      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
      "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.0",
        "es-define-property": "^1.0.0",
        "get-intrinsic": "^1.2.4",
        "set-function-length": "^1.2.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/call-bind-apply-helpers": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "function-bind": "^1.1.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/call-bound": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
      "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.2",
        "get-intrinsic": "^1.3.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/callsites": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/caniuse-lite": {
      "version": "1.0.30001723",
      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001723.tgz",
      "integrity": "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==",
      "funding": [
        {
          "type": "opencollective",
          "url": "https://opencollective.com/browserslist"
        },
        {
          "type": "tidelift",
          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
        },
        {
          "type": "github",
          "url": "https://github.com/sponsors/ai"
        }
      ],
      "license": "CC-BY-4.0"
    },
    "node_modules/chalk": {
      "version": "4.1.2",
      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "ansi-styles": "^4.1.0",
        "supports-color": "^7.1.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/chalk/chalk?sponsor=1"
      }
    },
    "node_modules/chownr": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
      "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
      "dev": true,
      "license": "BlueOak-1.0.0",
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/client-only": {
      "version": "0.0.1",
      "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
      "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
      "license": "MIT"
    },
    "node_modules/color": {
      "version": "4.2.3",
      "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
      "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "color-convert": "^2.0.1",
        "color-string": "^1.9.0"
      },
      "engines": {
        "node": ">=12.5.0"
      }
    },
    "node_modules/color-convert": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
      "devOptional": true,
      "license": "MIT",
      "dependencies": {
        "color-name": "~1.1.4"
      },
      "engines": {
        "node": ">=7.0.0"
      }
    },
    "node_modules/color-name": {
      "version": "1.1.4",
      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
      "devOptional": true,
      "license": "MIT"
    },
    "node_modules/color-string": {
      "version": "1.9.1",
      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "color-name": "^1.0.0",
        "simple-swizzle": "^0.2.2"
      }
    },
    "node_modules/concat-map": {
      "version": "0.0.1",
      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/cross-spawn": {
      "version": "7.0.6",
      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "path-key": "^3.1.0",
        "shebang-command": "^2.0.0",
        "which": "^2.0.1"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/csstype": {
      "version": "3.1.3",
      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/damerau-levenshtein": {
      "version": "1.0.8",
      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
      "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
      "dev": true,
      "license": "BSD-2-Clause"
    },
    "node_modules/data-view-buffer": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
      "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3",
        "es-errors": "^1.3.0",
        "is-data-view": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/data-view-byte-length": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
      "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3",
        "es-errors": "^1.3.0",
        "is-data-view": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/inspect-js"
      }
    },
    "node_modules/data-view-byte-offset": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
      "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "es-errors": "^1.3.0",
        "is-data-view": "^1.0.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/debug": {
      "version": "4.4.1",
      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
      "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "ms": "^2.1.3"
      },
      "engines": {
        "node": ">=6.0"
      },
      "peerDependenciesMeta": {
        "supports-color": {
          "optional": true
        }
      }
    },
    "node_modules/deep-is": {
      "version": "0.1.4",
      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/define-data-property": {
      "version": "1.1.4",
      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "es-define-property": "^1.0.0",
        "es-errors": "^1.3.0",
        "gopd": "^1.0.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/define-properties": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "define-data-property": "^1.0.1",
        "has-property-descriptors": "^1.0.0",
        "object-keys": "^1.1.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/detect-libc": {
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
      "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
      "devOptional": true,
      "license": "Apache-2.0",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/doctrine": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
      "dev": true,
      "license": "Apache-2.0",
      "dependencies": {
        "esutils": "^2.0.2"
      },
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/dunder-proto": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.1",
        "es-errors": "^1.3.0",
        "gopd": "^1.2.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/emoji-regex": {
      "version": "9.2.2",
      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/enhanced-resolve": {
      "version": "5.18.1",
      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
      "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "graceful-fs": "^4.2.4",
        "tapable": "^2.2.0"
      },
      "engines": {
        "node": ">=10.13.0"
      }
    },
    "node_modules/es-abstract": {
      "version": "1.24.0",
      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz",
      "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "array-buffer-byte-length": "^1.0.2",
        "arraybuffer.prototype.slice": "^1.0.4",
        "available-typed-arrays": "^1.0.7",
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.4",
        "data-view-buffer": "^1.0.2",
        "data-view-byte-length": "^1.0.2",
        "data-view-byte-offset": "^1.0.1",
        "es-define-property": "^1.0.1",
        "es-errors": "^1.3.0",
        "es-object-atoms": "^1.1.1",
        "es-set-tostringtag": "^2.1.0",
        "es-to-primitive": "^1.3.0",
        "function.prototype.name": "^1.1.8",
        "get-intrinsic": "^1.3.0",
        "get-proto": "^1.0.1",
        "get-symbol-description": "^1.1.0",
        "globalthis": "^1.0.4",
        "gopd": "^1.2.0",
        "has-property-descriptors": "^1.0.2",
        "has-proto": "^1.2.0",
        "has-symbols": "^1.1.0",
        "hasown": "^2.0.2",
        "internal-slot": "^1.1.0",
        "is-array-buffer": "^3.0.5",
        "is-callable": "^1.2.7",
        "is-data-view": "^1.0.2",
        "is-negative-zero": "^2.0.3",
        "is-regex": "^1.2.1",
        "is-set": "^2.0.3",
        "is-shared-array-buffer": "^1.0.4",
        "is-string": "^1.1.1",
        "is-typed-array": "^1.1.15",
        "is-weakref": "^1.1.1",
        "math-intrinsics": "^1.1.0",
        "object-inspect": "^1.13.4",
        "object-keys": "^1.1.1",
        "object.assign": "^4.1.7",
        "own-keys": "^1.0.1",
        "regexp.prototype.flags": "^1.5.4",
        "safe-array-concat": "^1.1.3",
        "safe-push-apply": "^1.0.0",
        "safe-regex-test": "^1.1.0",
        "set-proto": "^1.0.0",
        "stop-iteration-iterator": "^1.1.0",
        "string.prototype.trim": "^1.2.10",
        "string.prototype.trimend": "^1.0.9",
        "string.prototype.trimstart": "^1.0.8",
        "typed-array-buffer": "^1.0.3",
        "typed-array-byte-length": "^1.0.3",
        "typed-array-byte-offset": "^1.0.4",
        "typed-array-length": "^1.0.7",
        "unbox-primitive": "^1.1.0",
        "which-typed-array": "^1.1.19"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/es-define-property": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-errors": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-iterator-helpers": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz",
      "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.3",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.6",
        "es-errors": "^1.3.0",
        "es-set-tostringtag": "^2.0.3",
        "function-bind": "^1.1.2",
        "get-intrinsic": "^1.2.6",
        "globalthis": "^1.0.4",
        "gopd": "^1.2.0",
        "has-property-descriptors": "^1.0.2",
        "has-proto": "^1.2.0",
        "has-symbols": "^1.1.0",
        "internal-slot": "^1.1.0",
        "iterator.prototype": "^1.1.4",
        "safe-array-concat": "^1.1.3"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-object-atoms": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
      "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-set-tostringtag": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
      "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.6",
        "has-tostringtag": "^1.0.2",
        "hasown": "^2.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-shim-unscopables": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
      "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "hasown": "^2.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-to-primitive": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
      "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "is-callable": "^1.2.7",
        "is-date-object": "^1.0.5",
        "is-symbol": "^1.0.4"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/escape-string-regexp": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/eslint": {
      "version": "9.29.0",
      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
      "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@eslint-community/eslint-utils": "^4.2.0",
        "@eslint-community/regexpp": "^4.12.1",
        "@eslint/config-array": "^0.20.1",
        "@eslint/config-helpers": "^0.2.1",
        "@eslint/core": "^0.14.0",
        "@eslint/eslintrc": "^3.3.1",
        "@eslint/js": "9.29.0",
        "@eslint/plugin-kit": "^0.3.1",
        "@humanfs/node": "^0.16.6",
        "@humanwhocodes/module-importer": "^1.0.1",
        "@humanwhocodes/retry": "^0.4.2",
        "@types/estree": "^1.0.6",
        "@types/json-schema": "^7.0.15",
        "ajv": "^6.12.4",
        "chalk": "^4.0.0",
        "cross-spawn": "^7.0.6",
        "debug": "^4.3.2",
        "escape-string-regexp": "^4.0.0",
        "eslint-scope": "^8.4.0",
        "eslint-visitor-keys": "^4.2.1",
        "espree": "^10.4.0",
        "esquery": "^1.5.0",
        "esutils": "^2.0.2",
        "fast-deep-equal": "^3.1.3",
        "file-entry-cache": "^8.0.0",
        "find-up": "^5.0.0",
        "glob-parent": "^6.0.2",
        "ignore": "^5.2.0",
        "imurmurhash": "^0.1.4",
        "is-glob": "^4.0.0",
        "json-stable-stringify-without-jsonify": "^1.0.1",
        "lodash.merge": "^4.6.2",
        "minimatch": "^3.1.2",
        "natural-compare": "^1.4.0",
        "optionator": "^0.9.3"
      },
      "bin": {
        "eslint": "bin/eslint.js"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "url": "https://eslint.org/donate"
      },
      "peerDependencies": {
        "jiti": "*"
      },
      "peerDependenciesMeta": {
        "jiti": {
          "optional": true
        }
      }
    },
    "node_modules/eslint-config-next": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.3.4.tgz",
      "integrity": "sha512-WqeumCq57QcTP2lYlV6BRUySfGiBYEXlQ1L0mQ+u4N4X4ZhUVSSQ52WtjqHv60pJ6dD7jn+YZc0d1/ZSsxccvg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@next/eslint-plugin-next": "15.3.4",
        "@rushstack/eslint-patch": "^1.10.3",
        "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
        "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
        "eslint-import-resolver-node": "^0.3.6",
        "eslint-import-resolver-typescript": "^3.5.2",
        "eslint-plugin-import": "^2.31.0",
        "eslint-plugin-jsx-a11y": "^6.10.0",
        "eslint-plugin-react": "^7.37.0",
        "eslint-plugin-react-hooks": "^5.0.0"
      },
      "peerDependencies": {
        "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0",
        "typescript": ">=3.3.1"
      },
      "peerDependenciesMeta": {
        "typescript": {
          "optional": true
        }
      }
    },
    "node_modules/eslint-import-resolver-node": {
      "version": "0.3.9",
      "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
      "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "debug": "^3.2.7",
        "is-core-module": "^2.13.0",
        "resolve": "^1.22.4"
      }
    },
    "node_modules/eslint-import-resolver-node/node_modules/debug": {
      "version": "3.2.7",
      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "ms": "^2.1.1"
      }
    },
    "node_modules/eslint-import-resolver-typescript": {
      "version": "3.10.1",
      "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz",
      "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==",
      "dev": true,
      "license": "ISC",
      "dependencies": {
        "@nolyfill/is-core-module": "1.0.39",
        "debug": "^4.4.0",
        "get-tsconfig": "^4.10.0",
        "is-bun-module": "^2.0.0",
        "stable-hash": "^0.0.5",
        "tinyglobby": "^0.2.13",
        "unrs-resolver": "^1.6.2"
      },
      "engines": {
        "node": "^14.18.0 || >=16.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint-import-resolver-typescript"
      },
      "peerDependencies": {
        "eslint": "*",
        "eslint-plugin-import": "*",
        "eslint-plugin-import-x": "*"
      },
      "peerDependenciesMeta": {
        "eslint-plugin-import": {
          "optional": true
        },
        "eslint-plugin-import-x": {
          "optional": true
        }
      }
    },
    "node_modules/eslint-module-utils": {
      "version": "2.12.0",
      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz",
      "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "debug": "^3.2.7"
      },
      "engines": {
        "node": ">=4"
      },
      "peerDependenciesMeta": {
        "eslint": {
          "optional": true
        }
      }
    },
    "node_modules/eslint-module-utils/node_modules/debug": {
      "version": "3.2.7",
      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "ms": "^2.1.1"
      }
    },
    "node_modules/eslint-plugin-import": {
      "version": "2.31.0",
      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz",
      "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@rtsao/scc": "^1.1.0",
        "array-includes": "^3.1.8",
        "array.prototype.findlastindex": "^1.2.5",
        "array.prototype.flat": "^1.3.2",
        "array.prototype.flatmap": "^1.3.2",
        "debug": "^3.2.7",
        "doctrine": "^2.1.0",
        "eslint-import-resolver-node": "^0.3.9",
        "eslint-module-utils": "^2.12.0",
        "hasown": "^2.0.2",
        "is-core-module": "^2.15.1",
        "is-glob": "^4.0.3",
        "minimatch": "^3.1.2",
        "object.fromentries": "^2.0.8",
        "object.groupby": "^1.0.3",
        "object.values": "^1.2.0",
        "semver": "^6.3.1",
        "string.prototype.trimend": "^1.0.8",
        "tsconfig-paths": "^3.15.0"
      },
      "engines": {
        "node": ">=4"
      },
      "peerDependencies": {
        "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
      }
    },
    "node_modules/eslint-plugin-import/node_modules/debug": {
      "version": "3.2.7",
      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "ms": "^2.1.1"
      }
    },
    "node_modules/eslint-plugin-import/node_modules/semver": {
      "version": "6.3.1",
      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
      "dev": true,
      "license": "ISC",
      "bin": {
        "semver": "bin/semver.js"
      }
    },
    "node_modules/eslint-plugin-jsx-a11y": {
      "version": "6.10.2",
      "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz",
      "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "aria-query": "^5.3.2",
        "array-includes": "^3.1.8",
        "array.prototype.flatmap": "^1.3.2",
        "ast-types-flow": "^0.0.8",
        "axe-core": "^4.10.0",
        "axobject-query": "^4.1.0",
        "damerau-levenshtein": "^1.0.8",
        "emoji-regex": "^9.2.2",
        "hasown": "^2.0.2",
        "jsx-ast-utils": "^3.3.5",
        "language-tags": "^1.0.9",
        "minimatch": "^3.1.2",
        "object.fromentries": "^2.0.8",
        "safe-regex-test": "^1.0.3",
        "string.prototype.includes": "^2.0.1"
      },
      "engines": {
        "node": ">=4.0"
      },
      "peerDependencies": {
        "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
      }
    },
    "node_modules/eslint-plugin-react": {
      "version": "7.37.5",
      "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
      "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "array-includes": "^3.1.8",
        "array.prototype.findlast": "^1.2.5",
        "array.prototype.flatmap": "^1.3.3",
        "array.prototype.tosorted": "^1.1.4",
        "doctrine": "^2.1.0",
        "es-iterator-helpers": "^1.2.1",
        "estraverse": "^5.3.0",
        "hasown": "^2.0.2",
        "jsx-ast-utils": "^2.4.1 || ^3.0.0",
        "minimatch": "^3.1.2",
        "object.entries": "^1.1.9",
        "object.fromentries": "^2.0.8",
        "object.values": "^1.2.1",
        "prop-types": "^15.8.1",
        "resolve": "^2.0.0-next.5",
        "semver": "^6.3.1",
        "string.prototype.matchall": "^4.0.12",
        "string.prototype.repeat": "^1.0.0"
      },
      "engines": {
        "node": ">=4"
      },
      "peerDependencies": {
        "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
      }
    },
    "node_modules/eslint-plugin-react-hooks": {
      "version": "5.2.0",
      "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz",
      "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
      "peerDependencies": {
        "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
      }
    },
    "node_modules/eslint-plugin-react/node_modules/resolve": {
      "version": "2.0.0-next.5",
      "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
      "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "is-core-module": "^2.13.0",
        "path-parse": "^1.0.7",
        "supports-preserve-symlinks-flag": "^1.0.0"
      },
      "bin": {
        "resolve": "bin/resolve"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/eslint-plugin-react/node_modules/semver": {
      "version": "6.3.1",
      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
      "dev": true,
      "license": "ISC",
      "bin": {
        "semver": "bin/semver.js"
      }
    },
    "node_modules/eslint-scope": {
      "version": "8.4.0",
      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
      "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
      "dev": true,
      "license": "BSD-2-Clause",
      "dependencies": {
        "esrecurse": "^4.3.0",
        "estraverse": "^5.2.0"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint"
      }
    },
    "node_modules/eslint-visitor-keys": {
      "version": "4.2.1",
      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
      "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
      "dev": true,
      "license": "Apache-2.0",
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint"
      }
    },
    "node_modules/espree": {
      "version": "10.4.0",
      "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
      "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
      "dev": true,
      "license": "BSD-2-Clause",
      "dependencies": {
        "acorn": "^8.15.0",
        "acorn-jsx": "^5.3.2",
        "eslint-visitor-keys": "^4.2.1"
      },
      "engines": {
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint"
      }
    },
    "node_modules/esquery": {
      "version": "1.6.0",
      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
      "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
      "dev": true,
      "license": "BSD-3-Clause",
      "dependencies": {
        "estraverse": "^5.1.0"
      },
      "engines": {
        "node": ">=0.10"
      }
    },
    "node_modules/esrecurse": {
      "version": "4.3.0",
      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
      "dev": true,
      "license": "BSD-2-Clause",
      "dependencies": {
        "estraverse": "^5.2.0"
      },
      "engines": {
        "node": ">=4.0"
      }
    },
    "node_modules/estraverse": {
      "version": "5.3.0",
      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
      "dev": true,
      "license": "BSD-2-Clause",
      "engines": {
        "node": ">=4.0"
      }
    },
    "node_modules/esutils": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
      "dev": true,
      "license": "BSD-2-Clause",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/fast-deep-equal": {
      "version": "3.1.3",
      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/fast-glob": {
      "version": "3.3.1",
      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
      "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@nodelib/fs.stat": "^2.0.2",
        "@nodelib/fs.walk": "^1.2.3",
        "glob-parent": "^5.1.2",
        "merge2": "^1.3.0",
        "micromatch": "^4.0.4"
      },
      "engines": {
        "node": ">=8.6.0"
      }
    },
    "node_modules/fast-glob/node_modules/glob-parent": {
      "version": "5.1.2",
      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
      "dev": true,
      "license": "ISC",
      "dependencies": {
        "is-glob": "^4.0.1"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/fast-json-stable-stringify": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/fast-levenshtein": {
      "version": "2.0.6",
      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/fastq": {
      "version": "1.19.1",
      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
      "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
      "dev": true,
      "license": "ISC",
      "dependencies": {
        "reusify": "^1.0.4"
      }
    },
    "node_modules/file-entry-cache": {
      "version": "8.0.0",
      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
      "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "flat-cache": "^4.0.0"
      },
      "engines": {
        "node": ">=16.0.0"
      }
    },
    "node_modules/fill-range": {
      "version": "7.1.1",
      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "to-regex-range": "^5.0.1"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/find-up": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "locate-path": "^6.0.0",
        "path-exists": "^4.0.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/flat-cache": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
      "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "flatted": "^3.2.9",
        "keyv": "^4.5.4"
      },
      "engines": {
        "node": ">=16"
      }
    },
    "node_modules/flatted": {
      "version": "3.3.3",
      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
      "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
      "dev": true,
      "license": "ISC"
    },
    "node_modules/for-each": {
      "version": "0.3.5",
      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
      "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "is-callable": "^1.2.7"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/function-bind": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
      "dev": true,
      "license": "MIT",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/function.prototype.name": {
      "version": "1.1.8",
      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
      "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.3",
        "define-properties": "^1.2.1",
        "functions-have-names": "^1.2.3",
        "hasown": "^2.0.2",
        "is-callable": "^1.2.7"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/functions-have-names": {
      "version": "1.2.3",
      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
      "dev": true,
      "license": "MIT",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-intrinsic": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
      "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.2",
        "es-define-property": "^1.0.1",
        "es-errors": "^1.3.0",
        "es-object-atoms": "^1.1.1",
        "function-bind": "^1.1.2",
        "get-proto": "^1.0.1",
        "gopd": "^1.2.0",
        "has-symbols": "^1.1.0",
        "hasown": "^2.0.2",
        "math-intrinsics": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-proto": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
      "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "dunder-proto": "^1.0.1",
        "es-object-atoms": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/get-symbol-description": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
      "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3",
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.6"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-tsconfig": {
      "version": "4.10.1",
      "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz",
      "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "resolve-pkg-maps": "^1.0.0"
      },
      "funding": {
        "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
      }
    },
    "node_modules/glob-parent": {
      "version": "6.0.2",
      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
      "dev": true,
      "license": "ISC",
      "dependencies": {
        "is-glob": "^4.0.3"
      },
      "engines": {
        "node": ">=10.13.0"
      }
    },
    "node_modules/globals": {
      "version": "14.0.0",
      "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
      "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=18"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/globalthis": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
      "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "define-properties": "^1.2.1",
        "gopd": "^1.0.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/gopd": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/graceful-fs": {
      "version": "4.2.11",
      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
      "dev": true,
      "license": "ISC"
    },
    "node_modules/graphemer": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/has-bigints": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
      "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-flag": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/has-property-descriptors": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "es-define-property": "^1.0.0"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-proto": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
      "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "dunder-proto": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-symbols": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-tostringtag": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "has-symbols": "^1.0.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/hasown": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "function-bind": "^1.1.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/ignore": {
      "version": "5.3.2",
      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
      "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 4"
      }
    },
    "node_modules/import-fresh": {
      "version": "3.3.1",
      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
      "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "parent-module": "^1.0.0",
        "resolve-from": "^4.0.0"
      },
      "engines": {
        "node": ">=6"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/imurmurhash": {
      "version": "0.1.4",
      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=0.8.19"
      }
    },
    "node_modules/internal-slot": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
      "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "hasown": "^2.0.2",
        "side-channel": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/is-array-buffer": {
      "version": "3.0.5",
      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
      "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.3",
        "get-intrinsic": "^1.2.6"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-arrayish": {
      "version": "0.3.2",
      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
      "license": "MIT",
      "optional": true
    },
    "node_modules/is-async-function": {
      "version": "2.1.1",
      "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
      "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "async-function": "^1.0.0",
        "call-bound": "^1.0.3",
        "get-proto": "^1.0.1",
        "has-tostringtag": "^1.0.2",
        "safe-regex-test": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-bigint": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
      "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "has-bigints": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-boolean-object": {
      "version": "1.2.2",
      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
      "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3",
        "has-tostringtag": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-bun-module": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz",
      "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "semver": "^7.7.1"
      }
    },
    "node_modules/is-callable": {
      "version": "1.2.7",
      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-core-module": {
      "version": "2.16.1",
      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
      "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "hasown": "^2.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-data-view": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
      "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "get-intrinsic": "^1.2.6",
        "is-typed-array": "^1.1.13"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-date-object": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
      "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "has-tostringtag": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-extglob": {
      "version": "2.1.1",
      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/is-finalizationregistry": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
      "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-generator-function": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz",
      "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3",
        "get-proto": "^1.0.0",
        "has-tostringtag": "^1.0.2",
        "safe-regex-test": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-glob": {
      "version": "4.0.3",
      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "is-extglob": "^2.1.1"
      },
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/is-map": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
      "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-negative-zero": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
      "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-number": {
      "version": "7.0.0",
      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=0.12.0"
      }
    },
    "node_modules/is-number-object": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
      "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3",
        "has-tostringtag": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-regex": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
      "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "gopd": "^1.2.0",
        "has-tostringtag": "^1.0.2",
        "hasown": "^2.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-set": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
      "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-shared-array-buffer": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
      "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-string": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
      "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3",
        "has-tostringtag": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-symbol": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
      "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "has-symbols": "^1.1.0",
        "safe-regex-test": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-typed-array": {
      "version": "1.1.15",
      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
      "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "which-typed-array": "^1.1.16"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-weakmap": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
      "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-weakref": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
      "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-weakset": {
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
      "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3",
        "get-intrinsic": "^1.2.6"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/isarray": {
      "version": "2.0.5",
      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/isexe": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
      "dev": true,
      "license": "ISC"
    },
    "node_modules/iterator.prototype": {
      "version": "1.1.5",
      "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz",
      "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "define-data-property": "^1.1.4",
        "es-object-atoms": "^1.0.0",
        "get-intrinsic": "^1.2.6",
        "get-proto": "^1.0.0",
        "has-symbols": "^1.1.0",
        "set-function-name": "^2.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/jiti": {
      "version": "2.4.2",
      "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
      "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
      "dev": true,
      "license": "MIT",
      "bin": {
        "jiti": "lib/jiti-cli.mjs"
      }
    },
    "node_modules/js-tokens": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/js-yaml": {
      "version": "4.1.0",
      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "argparse": "^2.0.1"
      },
      "bin": {
        "js-yaml": "bin/js-yaml.js"
      }
    },
    "node_modules/json-buffer": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/json-schema-traverse": {
      "version": "0.4.1",
      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/json-stable-stringify-without-jsonify": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/json5": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
      "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "minimist": "^1.2.0"
      },
      "bin": {
        "json5": "lib/cli.js"
      }
    },
    "node_modules/jsx-ast-utils": {
      "version": "3.3.5",
      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
      "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "array-includes": "^3.1.6",
        "array.prototype.flat": "^1.3.1",
        "object.assign": "^4.1.4",
        "object.values": "^1.1.6"
      },
      "engines": {
        "node": ">=4.0"
      }
    },
    "node_modules/keyv": {
      "version": "4.5.4",
      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "json-buffer": "3.0.1"
      }
    },
    "node_modules/language-subtag-registry": {
      "version": "0.3.23",
      "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
      "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==",
      "dev": true,
      "license": "CC0-1.0"
    },
    "node_modules/language-tags": {
      "version": "1.0.9",
      "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz",
      "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "language-subtag-registry": "^0.3.20"
      },
      "engines": {
        "node": ">=0.10"
      }
    },
    "node_modules/levn": {
      "version": "0.4.1",
      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "prelude-ls": "^1.2.1",
        "type-check": "~0.4.0"
      },
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/lightningcss": {
      "version": "1.30.1",
      "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
      "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
      "dev": true,
      "license": "MPL-2.0",
      "dependencies": {
        "detect-libc": "^2.0.3"
      },
      "engines": {
        "node": ">= 12.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/parcel"
      },
      "optionalDependencies": {
        "lightningcss-darwin-arm64": "1.30.1",
        "lightningcss-darwin-x64": "1.30.1",
        "lightningcss-freebsd-x64": "1.30.1",
        "lightningcss-linux-arm-gnueabihf": "1.30.1",
        "lightningcss-linux-arm64-gnu": "1.30.1",
        "lightningcss-linux-arm64-musl": "1.30.1",
        "lightningcss-linux-x64-gnu": "1.30.1",
        "lightningcss-linux-x64-musl": "1.30.1",
        "lightningcss-win32-arm64-msvc": "1.30.1",
        "lightningcss-win32-x64-msvc": "1.30.1"
      }
    },
    "node_modules/lightningcss-darwin-arm64": {
      "version": "1.30.1",
      "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz",
      "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MPL-2.0",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">= 12.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/parcel"
      }
    },
    "node_modules/lightningcss-darwin-x64": {
      "version": "1.30.1",
      "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz",
      "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MPL-2.0",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">= 12.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/parcel"
      }
    },
    "node_modules/lightningcss-freebsd-x64": {
      "version": "1.30.1",
      "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz",
      "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MPL-2.0",
      "optional": true,
      "os": [
        "freebsd"
      ],
      "engines": {
        "node": ">= 12.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/parcel"
      }
    },
    "node_modules/lightningcss-linux-arm-gnueabihf": {
      "version": "1.30.1",
      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz",
      "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==",
      "cpu": [
        "arm"
      ],
      "dev": true,
      "license": "MPL-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 12.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/parcel"
      }
    },
    "node_modules/lightningcss-linux-arm64-gnu": {
      "version": "1.30.1",
      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz",
      "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MPL-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 12.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/parcel"
      }
    },
    "node_modules/lightningcss-linux-arm64-musl": {
      "version": "1.30.1",
      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz",
      "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MPL-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 12.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/parcel"
      }
    },
    "node_modules/lightningcss-linux-x64-gnu": {
      "version": "1.30.1",
      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz",
      "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MPL-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 12.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/parcel"
      }
    },
    "node_modules/lightningcss-linux-x64-musl": {
      "version": "1.30.1",
      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz",
      "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MPL-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">= 12.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/parcel"
      }
    },
    "node_modules/lightningcss-win32-arm64-msvc": {
      "version": "1.30.1",
      "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz",
      "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MPL-2.0",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">= 12.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/parcel"
      }
    },
    "node_modules/lightningcss-win32-x64-msvc": {
      "version": "1.30.1",
      "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz",
      "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MPL-2.0",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">= 12.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/parcel"
      }
    },
    "node_modules/locate-path": {
      "version": "6.0.0",
      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "p-locate": "^5.0.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/lodash.merge": {
      "version": "4.6.2",
      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/loose-envify": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "js-tokens": "^3.0.0 || ^4.0.0"
      },
      "bin": {
        "loose-envify": "cli.js"
      }
    },
    "node_modules/magic-string": {
      "version": "0.30.17",
      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
      "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@jridgewell/sourcemap-codec": "^1.5.0"
      }
    },
    "node_modules/math-intrinsics": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/merge2": {
      "version": "1.4.1",
      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/micromatch": {
      "version": "4.0.8",
      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "braces": "^3.0.3",
        "picomatch": "^2.3.1"
      },
      "engines": {
        "node": ">=8.6"
      }
    },
    "node_modules/minimatch": {
      "version": "3.1.2",
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
      "dev": true,
      "license": "ISC",
      "dependencies": {
        "brace-expansion": "^1.1.7"
      },
      "engines": {
        "node": "*"
      }
    },
    "node_modules/minimist": {
      "version": "1.2.8",
      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
      "dev": true,
      "license": "MIT",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/minipass": {
      "version": "7.1.2",
      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
      "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
      "dev": true,
      "license": "ISC",
      "engines": {
        "node": ">=16 || 14 >=14.17"
      }
    },
    "node_modules/minizlib": {
      "version": "3.0.2",
      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
      "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "minipass": "^7.1.2"
      },
      "engines": {
        "node": ">= 18"
      }
    },
    "node_modules/mkdirp": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
      "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
      "dev": true,
      "license": "MIT",
      "bin": {
        "mkdirp": "dist/cjs/src/bin.js"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
    "node_modules/ms": {
      "version": "2.1.3",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/nanoid": {
      "version": "3.3.11",
      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
      "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/ai"
        }
      ],
      "license": "MIT",
      "bin": {
        "nanoid": "bin/nanoid.cjs"
      },
      "engines": {
        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
      }
    },
    "node_modules/napi-postinstall": {
      "version": "0.2.4",
      "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.4.tgz",
      "integrity": "sha512-ZEzHJwBhZ8qQSbknHqYcdtQVr8zUgGyM/q6h6qAyhtyVMNrSgDhrC4disf03dYW0e+czXyLnZINnCTEkWy0eJg==",
      "dev": true,
      "license": "MIT",
      "bin": {
        "napi-postinstall": "lib/cli.js"
      },
      "engines": {
        "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/napi-postinstall"
      }
    },
    "node_modules/natural-compare": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/next": {
      "version": "15.3.4",
      "resolved": "https://registry.npmjs.org/next/-/next-15.3.4.tgz",
      "integrity": "sha512-mHKd50C+mCjam/gcnwqL1T1vPx/XQNFlXqFIVdgQdVAFY9iIQtY0IfaVflEYzKiqjeA7B0cYYMaCrmAYFjs4rA==",
      "license": "MIT",
      "dependencies": {
        "@next/env": "15.3.4",
        "@swc/counter": "0.1.3",
        "@swc/helpers": "0.5.15",
        "busboy": "1.6.0",
        "caniuse-lite": "^1.0.30001579",
        "postcss": "8.4.31",
        "styled-jsx": "5.1.6"
      },
      "bin": {
        "next": "dist/bin/next"
      },
      "engines": {
        "node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
      },
      "optionalDependencies": {
        "@next/swc-darwin-arm64": "15.3.4",
        "@next/swc-darwin-x64": "15.3.4",
        "@next/swc-linux-arm64-gnu": "15.3.4",
        "@next/swc-linux-arm64-musl": "15.3.4",
        "@next/swc-linux-x64-gnu": "15.3.4",
        "@next/swc-linux-x64-musl": "15.3.4",
        "@next/swc-win32-arm64-msvc": "15.3.4",
        "@next/swc-win32-x64-msvc": "15.3.4",
        "sharp": "^0.34.1"
      },
      "peerDependencies": {
        "@opentelemetry/api": "^1.1.0",
        "@playwright/test": "^1.41.2",
        "babel-plugin-react-compiler": "*",
        "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
        "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
        "sass": "^1.3.0"
      },
      "peerDependenciesMeta": {
        "@opentelemetry/api": {
          "optional": true
        },
        "@playwright/test": {
          "optional": true
        },
        "babel-plugin-react-compiler": {
          "optional": true
        },
        "sass": {
          "optional": true
        }
      }
    },
    "node_modules/next/node_modules/postcss": {
      "version": "8.4.31",
      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
      "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
      "funding": [
        {
          "type": "opencollective",
          "url": "https://opencollective.com/postcss/"
        },
        {
          "type": "tidelift",
          "url": "https://tidelift.com/funding/github/npm/postcss"
        },
        {
          "type": "github",
          "url": "https://github.com/sponsors/ai"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "nanoid": "^3.3.6",
        "picocolors": "^1.0.0",
        "source-map-js": "^1.0.2"
      },
      "engines": {
        "node": "^10 || ^12 || >=14"
      }
    },
    "node_modules/node-appwrite": {
      "version": "17.0.0",
      "resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-17.0.0.tgz",
      "integrity": "sha512-5Moi5ENPnoAfU1/6CZP9K2NTuB6Nm3dSyhokno+24RDuP7czjXCdwzfeyjmyHieggbrLkN89AYSOv9W1XkCL9w==",
      "license": "BSD-3-Clause",
      "dependencies": {
        "node-fetch-native-with-agent": "1.7.2"
      }
    },
    "node_modules/node-fetch-native-with-agent": {
      "version": "1.7.2",
      "resolved": "https://registry.npmjs.org/node-fetch-native-with-agent/-/node-fetch-native-with-agent-1.7.2.tgz",
      "integrity": "sha512-5MaOOCuJEvcckoz7/tjdx1M6OusOY6Xc5f459IaruGStWnKzlI1qpNgaAwmn4LmFYcsSlj+jBMk84wmmRxfk5g==",
      "license": "MIT"
    },
    "node_modules/object-assign": {
      "version": "4.1.1",
      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/object-inspect": {
      "version": "1.13.4",
      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
      "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/object-keys": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/object.assign": {
      "version": "4.1.7",
      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
      "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.3",
        "define-properties": "^1.2.1",
        "es-object-atoms": "^1.0.0",
        "has-symbols": "^1.1.0",
        "object-keys": "^1.1.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/object.entries": {
      "version": "1.1.9",
      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
      "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.4",
        "define-properties": "^1.2.1",
        "es-object-atoms": "^1.1.1"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/object.fromentries": {
      "version": "2.0.8",
      "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
      "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.7",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.2",
        "es-object-atoms": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/object.groupby": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
      "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.7",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/object.values": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
      "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.3",
        "define-properties": "^1.2.1",
        "es-object-atoms": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/optionator": {
      "version": "0.9.4",
      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "deep-is": "^0.1.3",
        "fast-levenshtein": "^2.0.6",
        "levn": "^0.4.1",
        "prelude-ls": "^1.2.1",
        "type-check": "^0.4.0",
        "word-wrap": "^1.2.5"
      },
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/own-keys": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
      "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "get-intrinsic": "^1.2.6",
        "object-keys": "^1.1.1",
        "safe-push-apply": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/p-limit": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "yocto-queue": "^0.1.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/p-locate": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "p-limit": "^3.0.2"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/parent-module": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "callsites": "^3.0.0"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/path-exists": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/path-key": {
      "version": "3.1.1",
      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/path-parse": {
      "version": "1.0.7",
      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/picocolors": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
      "license": "ISC"
    },
    "node_modules/picomatch": {
      "version": "2.3.1",
      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=8.6"
      },
      "funding": {
        "url": "https://github.com/sponsors/jonschlinkert"
      }
    },
    "node_modules/possible-typed-array-names": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
      "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/postcss": {
      "version": "8.5.6",
      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
      "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
      "dev": true,
      "funding": [
        {
          "type": "opencollective",
          "url": "https://opencollective.com/postcss/"
        },
        {
          "type": "tidelift",
          "url": "https://tidelift.com/funding/github/npm/postcss"
        },
        {
          "type": "github",
          "url": "https://github.com/sponsors/ai"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "nanoid": "^3.3.11",
        "picocolors": "^1.1.1",
        "source-map-js": "^1.2.1"
      },
      "engines": {
        "node": "^10 || ^12 || >=14"
      }
    },
    "node_modules/prelude-ls": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/prop-types": {
      "version": "15.8.1",
      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
      "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "loose-envify": "^1.4.0",
        "object-assign": "^4.1.1",
        "react-is": "^16.13.1"
      }
    },
    "node_modules/punycode": {
      "version": "2.3.1",
      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/queue-microtask": {
      "version": "1.2.3",
      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
      "dev": true,
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT"
    },
    "node_modules/react": {
      "version": "19.1.0",
      "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
      "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
      "license": "MIT",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/react-dom": {
      "version": "19.1.0",
      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
      "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
      "license": "MIT",
      "dependencies": {
        "scheduler": "^0.26.0"
      },
      "peerDependencies": {
        "react": "^19.1.0"
      }
    },
    "node_modules/react-is": {
      "version": "16.13.1",
      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/reflect.getprototypeof": {
      "version": "1.0.10",
      "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
      "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.9",
        "es-errors": "^1.3.0",
        "es-object-atoms": "^1.0.0",
        "get-intrinsic": "^1.2.7",
        "get-proto": "^1.0.1",
        "which-builtin-type": "^1.2.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/regexp.prototype.flags": {
      "version": "1.5.4",
      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
      "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "define-properties": "^1.2.1",
        "es-errors": "^1.3.0",
        "get-proto": "^1.0.1",
        "gopd": "^1.2.0",
        "set-function-name": "^2.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/resolve": {
      "version": "1.22.10",
      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
      "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "is-core-module": "^2.16.0",
        "path-parse": "^1.0.7",
        "supports-preserve-symlinks-flag": "^1.0.0"
      },
      "bin": {
        "resolve": "bin/resolve"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/resolve-from": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/resolve-pkg-maps": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
      "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
      "dev": true,
      "license": "MIT",
      "funding": {
        "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
      }
    },
    "node_modules/reusify": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "iojs": ">=1.0.0",
        "node": ">=0.10.0"
      }
    },
    "node_modules/run-parallel": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
      "dev": true,
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "queue-microtask": "^1.2.2"
      }
    },
    "node_modules/safe-array-concat": {
      "version": "1.1.3",
      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
      "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.2",
        "get-intrinsic": "^1.2.6",
        "has-symbols": "^1.1.0",
        "isarray": "^2.0.5"
      },
      "engines": {
        "node": ">=0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/safe-push-apply": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
      "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "isarray": "^2.0.5"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/safe-regex-test": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
      "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "es-errors": "^1.3.0",
        "is-regex": "^1.2.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/scheduler": {
      "version": "0.26.0",
      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
      "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
      "license": "MIT"
    },
    "node_modules/semver": {
      "version": "7.7.2",
      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
      "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
      "devOptional": true,
      "license": "ISC",
      "bin": {
        "semver": "bin/semver.js"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/set-function-length": {
      "version": "1.2.2",
      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "define-data-property": "^1.1.4",
        "es-errors": "^1.3.0",
        "function-bind": "^1.1.2",
        "get-intrinsic": "^1.2.4",
        "gopd": "^1.0.1",
        "has-property-descriptors": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/set-function-name": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
      "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "define-data-property": "^1.1.4",
        "es-errors": "^1.3.0",
        "functions-have-names": "^1.2.3",
        "has-property-descriptors": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/set-proto": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
      "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "dunder-proto": "^1.0.1",
        "es-errors": "^1.3.0",
        "es-object-atoms": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/sharp": {
      "version": "0.34.2",
      "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.2.tgz",
      "integrity": "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==",
      "hasInstallScript": true,
      "license": "Apache-2.0",
      "optional": true,
      "dependencies": {
        "color": "^4.2.3",
        "detect-libc": "^2.0.4",
        "semver": "^7.7.2"
      },
      "engines": {
        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/libvips"
      },
      "optionalDependencies": {
        "@img/sharp-darwin-arm64": "0.34.2",
        "@img/sharp-darwin-x64": "0.34.2",
        "@img/sharp-libvips-darwin-arm64": "1.1.0",
        "@img/sharp-libvips-darwin-x64": "1.1.0",
        "@img/sharp-libvips-linux-arm": "1.1.0",
        "@img/sharp-libvips-linux-arm64": "1.1.0",
        "@img/sharp-libvips-linux-ppc64": "1.1.0",
        "@img/sharp-libvips-linux-s390x": "1.1.0",
        "@img/sharp-libvips-linux-x64": "1.1.0",
        "@img/sharp-libvips-linuxmusl-arm64": "1.1.0",
        "@img/sharp-libvips-linuxmusl-x64": "1.1.0",
        "@img/sharp-linux-arm": "0.34.2",
        "@img/sharp-linux-arm64": "0.34.2",
        "@img/sharp-linux-s390x": "0.34.2",
        "@img/sharp-linux-x64": "0.34.2",
        "@img/sharp-linuxmusl-arm64": "0.34.2",
        "@img/sharp-linuxmusl-x64": "0.34.2",
        "@img/sharp-wasm32": "0.34.2",
        "@img/sharp-win32-arm64": "0.34.2",
        "@img/sharp-win32-ia32": "0.34.2",
        "@img/sharp-win32-x64": "0.34.2"
      }
    },
    "node_modules/shebang-command": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "shebang-regex": "^3.0.0"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/shebang-regex": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/side-channel": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
      "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "object-inspect": "^1.13.3",
        "side-channel-list": "^1.0.0",
        "side-channel-map": "^1.0.1",
        "side-channel-weakmap": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/side-channel-list": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
      "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "object-inspect": "^1.13.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/side-channel-map": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
      "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.5",
        "object-inspect": "^1.13.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/side-channel-weakmap": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
      "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.5",
        "object-inspect": "^1.13.3",
        "side-channel-map": "^1.0.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/simple-swizzle": {
      "version": "0.2.2",
      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "is-arrayish": "^0.3.1"
      }
    },
    "node_modules/source-map-js": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
      "license": "BSD-3-Clause",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/stable-hash": {
      "version": "0.0.5",
      "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz",
      "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/stop-iteration-iterator": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
      "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "internal-slot": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/streamsearch": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
      "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
      "engines": {
        "node": ">=10.0.0"
      }
    },
    "node_modules/string.prototype.includes": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
      "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.7",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.3"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/string.prototype.matchall": {
      "version": "4.0.12",
      "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
      "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.3",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.6",
        "es-errors": "^1.3.0",
        "es-object-atoms": "^1.0.0",
        "get-intrinsic": "^1.2.6",
        "gopd": "^1.2.0",
        "has-symbols": "^1.1.0",
        "internal-slot": "^1.1.0",
        "regexp.prototype.flags": "^1.5.3",
        "set-function-name": "^2.0.2",
        "side-channel": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/string.prototype.repeat": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
      "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "define-properties": "^1.1.3",
        "es-abstract": "^1.17.5"
      }
    },
    "node_modules/string.prototype.trim": {
      "version": "1.2.10",
      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
      "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.2",
        "define-data-property": "^1.1.4",
        "define-properties": "^1.2.1",
        "es-abstract": "^1.23.5",
        "es-object-atoms": "^1.0.0",
        "has-property-descriptors": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/string.prototype.trimend": {
      "version": "1.0.9",
      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
      "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.2",
        "define-properties": "^1.2.1",
        "es-object-atoms": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/string.prototype.trimstart": {
      "version": "1.0.8",
      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
      "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.7",
        "define-properties": "^1.2.1",
        "es-object-atoms": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/strip-bom": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
      "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/strip-json-comments": {
      "version": "3.1.1",
      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=8"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/styled-jsx": {
      "version": "5.1.6",
      "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
      "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
      "license": "MIT",
      "dependencies": {
        "client-only": "0.0.1"
      },
      "engines": {
        "node": ">= 12.0.0"
      },
      "peerDependencies": {
        "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
      },
      "peerDependenciesMeta": {
        "@babel/core": {
          "optional": true
        },
        "babel-plugin-macros": {
          "optional": true
        }
      }
    },
    "node_modules/supports-color": {
      "version": "7.2.0",
      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "has-flag": "^4.0.0"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/supports-preserve-symlinks-flag": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/tailwindcss": {
      "version": "4.1.10",
      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.10.tgz",
      "integrity": "sha512-P3nr6WkvKV/ONsTzj6Gb57sWPMX29EPNPopo7+FcpkQaNsrNpZ1pv8QmrYI2RqEKD7mlGqLnGovlcYnBK0IqUA==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/tapable": {
      "version": "2.2.2",
      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
      "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/tar": {
      "version": "7.4.3",
      "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
      "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
      "dev": true,
      "license": "ISC",
      "dependencies": {
        "@isaacs/fs-minipass": "^4.0.0",
        "chownr": "^3.0.0",
        "minipass": "^7.1.2",
        "minizlib": "^3.0.1",
        "mkdirp": "^3.0.1",
        "yallist": "^5.0.0"
      },
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/tinyglobby": {
      "version": "0.2.14",
      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
      "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "fdir": "^6.4.4",
        "picomatch": "^4.0.2"
      },
      "engines": {
        "node": ">=12.0.0"
      },
      "funding": {
        "url": "https://github.com/sponsors/SuperchupuDev"
      }
    },
    "node_modules/tinyglobby/node_modules/fdir": {
      "version": "6.4.6",
      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
      "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
      "dev": true,
      "license": "MIT",
      "peerDependencies": {
        "picomatch": "^3 || ^4"
      },
      "peerDependenciesMeta": {
        "picomatch": {
          "optional": true
        }
      }
    },
    "node_modules/tinyglobby/node_modules/picomatch": {
      "version": "4.0.2",
      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
      "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=12"
      },
      "funding": {
        "url": "https://github.com/sponsors/jonschlinkert"
      }
    },
    "node_modules/to-regex-range": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "is-number": "^7.0.0"
      },
      "engines": {
        "node": ">=8.0"
      }
    },
    "node_modules/ts-api-utils": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
      "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=18.12"
      },
      "peerDependencies": {
        "typescript": ">=4.8.4"
      }
    },
    "node_modules/tsconfig-paths": {
      "version": "3.15.0",
      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
      "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@types/json5": "^0.0.29",
        "json5": "^1.0.2",
        "minimist": "^1.2.6",
        "strip-bom": "^3.0.0"
      }
    },
    "node_modules/tslib": {
      "version": "2.8.1",
      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
      "license": "0BSD"
    },
    "node_modules/type-check": {
      "version": "0.4.0",
      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "prelude-ls": "^1.2.1"
      },
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/typed-array-buffer": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
      "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3",
        "es-errors": "^1.3.0",
        "is-typed-array": "^1.1.14"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/typed-array-byte-length": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
      "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.8",
        "for-each": "^0.3.3",
        "gopd": "^1.2.0",
        "has-proto": "^1.2.0",
        "is-typed-array": "^1.1.14"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/typed-array-byte-offset": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
      "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "available-typed-arrays": "^1.0.7",
        "call-bind": "^1.0.8",
        "for-each": "^0.3.3",
        "gopd": "^1.2.0",
        "has-proto": "^1.2.0",
        "is-typed-array": "^1.1.15",
        "reflect.getprototypeof": "^1.0.9"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/typed-array-length": {
      "version": "1.0.7",
      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
      "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bind": "^1.0.7",
        "for-each": "^0.3.3",
        "gopd": "^1.0.1",
        "is-typed-array": "^1.1.13",
        "possible-typed-array-names": "^1.0.0",
        "reflect.getprototypeof": "^1.0.6"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/typescript": {
      "version": "5.8.3",
      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
      "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
      "dev": true,
      "license": "Apache-2.0",
      "bin": {
        "tsc": "bin/tsc",
        "tsserver": "bin/tsserver"
      },
      "engines": {
        "node": ">=14.17"
      }
    },
    "node_modules/unbox-primitive": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
      "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.3",
        "has-bigints": "^1.0.2",
        "has-symbols": "^1.1.0",
        "which-boxed-primitive": "^1.1.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/undici-types": {
      "version": "6.21.0",
      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
      "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/unrs-resolver": {
      "version": "1.9.0",
      "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.9.0.tgz",
      "integrity": "sha512-wqaRu4UnzBD2ABTC1kLfBjAqIDZ5YUTr/MLGa7By47JV1bJDSW7jq/ZSLigB7enLe7ubNaJhtnBXgrc/50cEhg==",
      "dev": true,
      "hasInstallScript": true,
      "license": "MIT",
      "dependencies": {
        "napi-postinstall": "^0.2.2"
      },
      "funding": {
        "url": "https://opencollective.com/unrs-resolver"
      },
      "optionalDependencies": {
        "@unrs/resolver-binding-android-arm-eabi": "1.9.0",
        "@unrs/resolver-binding-android-arm64": "1.9.0",
        "@unrs/resolver-binding-darwin-arm64": "1.9.0",
        "@unrs/resolver-binding-darwin-x64": "1.9.0",
        "@unrs/resolver-binding-freebsd-x64": "1.9.0",
        "@unrs/resolver-binding-linux-arm-gnueabihf": "1.9.0",
        "@unrs/resolver-binding-linux-arm-musleabihf": "1.9.0",
        "@unrs/resolver-binding-linux-arm64-gnu": "1.9.0",
        "@unrs/resolver-binding-linux-arm64-musl": "1.9.0",
        "@unrs/resolver-binding-linux-ppc64-gnu": "1.9.0",
        "@unrs/resolver-binding-linux-riscv64-gnu": "1.9.0",
        "@unrs/resolver-binding-linux-riscv64-musl": "1.9.0",
        "@unrs/resolver-binding-linux-s390x-gnu": "1.9.0",
        "@unrs/resolver-binding-linux-x64-gnu": "1.9.0",
        "@unrs/resolver-binding-linux-x64-musl": "1.9.0",
        "@unrs/resolver-binding-wasm32-wasi": "1.9.0",
        "@unrs/resolver-binding-win32-arm64-msvc": "1.9.0",
        "@unrs/resolver-binding-win32-ia32-msvc": "1.9.0",
        "@unrs/resolver-binding-win32-x64-msvc": "1.9.0"
      }
    },
    "node_modules/uri-js": {
      "version": "4.4.1",
      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
      "dev": true,
      "license": "BSD-2-Clause",
      "dependencies": {
        "punycode": "^2.1.0"
      }
    },
    "node_modules/which": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
      "dev": true,
      "license": "ISC",
      "dependencies": {
        "isexe": "^2.0.0"
      },
      "bin": {
        "node-which": "bin/node-which"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/which-boxed-primitive": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
      "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "is-bigint": "^1.1.0",
        "is-boolean-object": "^1.2.1",
        "is-number-object": "^1.1.1",
        "is-string": "^1.1.1",
        "is-symbol": "^1.1.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/which-builtin-type": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
      "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "function.prototype.name": "^1.1.6",
        "has-tostringtag": "^1.0.2",
        "is-async-function": "^2.0.0",
        "is-date-object": "^1.1.0",
        "is-finalizationregistry": "^1.1.0",
        "is-generator-function": "^1.0.10",
        "is-regex": "^1.2.1",
        "is-weakref": "^1.0.2",
        "isarray": "^2.0.5",
        "which-boxed-primitive": "^1.1.0",
        "which-collection": "^1.0.2",
        "which-typed-array": "^1.1.16"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/which-collection": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
      "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "is-map": "^2.0.3",
        "is-set": "^2.0.3",
        "is-weakmap": "^2.0.2",
        "is-weakset": "^2.0.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/which-typed-array": {
      "version": "1.1.19",
      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
      "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "available-typed-arrays": "^1.0.7",
        "call-bind": "^1.0.8",
        "call-bound": "^1.0.4",
        "for-each": "^0.3.5",
        "get-proto": "^1.0.1",
        "gopd": "^1.2.0",
        "has-tostringtag": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/word-wrap": {
      "version": "1.2.5",
      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
      "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/yallist": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
      "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
      "dev": true,
      "license": "BlueOak-1.0.0",
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/yocto-queue": {
      "version": "0.1.0",
      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    }
  }
}


package.json

{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "appwrite": "^18.1.1",
    "next": "15.3.4",
    "node-appwrite": "^17.0.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "devDependencies": {
    "@eslint/eslintrc": "^3",
    "@tailwindcss/postcss": "^4",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^9",
    "eslint-config-next": "15.3.4",
    "tailwindcss": "^4",
    "typescript": "^5"
  }
}


postcss.config.mjs

const config = {
  plugins: ["@tailwindcss/postcss"],
};

export default config;


public/file.svg

<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

public/globe.svg

<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

public/next.svg

<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

public/vercel.svg

<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

public/window.svg

<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

src/app/api/carrinhos/[id]/route.ts

import { NextResponse, unstable_rootParams } from 'next/server';

export const runtime = 'edge';

export async function PATCH(request: Request) {
  const { id } = await unstable_rootParams();
  console.log('🔄 [API] Atualizando carrinho:', id);

  try {
    const body = await request.json();
    console.log('📤 [API] Dados para atualização:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CARRINHOS_ID!}/documents/${id}`,
      {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    if (response.ok) {
      const data = await response.json();
      console.log('✅ [API] Carrinho atualizado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao atualizar:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao atualizar carrinho', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na atualização:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}

export async function DELETE() {
  const { id } = await unstable_rootParams();
  console.log('🗑️ [API] Excluindo carrinho:', id);

  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CARRINHOS_ID!}/documents/${id}`,
      {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        }
      }
    );

    if (response.ok || response.status === 204) {
      console.log('✅ [API] Carrinho excluído com sucesso!');
      return NextResponse.json({ success: true });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao excluir:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao excluir carrinho', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na exclusão:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/carrinhos/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { Client, Databases, Query } from 'node-appwrite';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  console.log('📋 [API] Listando carrinhos...');

  try {
    const apiKey = process.env.APPWRITE_API_KEY;
    if (!apiKey) {
      console.error('❌ [API] APPWRITE_API_KEY não configurada');
      return NextResponse.json(
        { success: false, error: 'Configuração do servidor ausente' },
        { status: 500 }
      );
    }

    const endpoint = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!;
    const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!;
    const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
    const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CARRINHOS_ID!;

    const { searchParams } = new URL(request.url);
    const limit = Number(searchParams.get('limit')) || 10;
    const page = Number(searchParams.get('page')) || 1;
    const termoBuscado = searchParams.get('termoBuscado') || '';
    const offset = (page - 1) * limit;

    const client = new Client()
      .setEndpoint(endpoint)
      .setProject(projectId)
      .setKey(apiKey);

    const databases = new Databases(client);

    const queries = [
      termoBuscado ? Query.equal('usuarios', termoBuscado) : Query.limit(limit),
      Query.limit(limit),
      Query.offset(offset)
    ];

    const response = await databases.listDocuments(databaseId, collectionId, queries);

    console.log(`✅ [API] ${response.total} carrinhos carregados!`);
    return NextResponse.json({
      success: true,
      documents: response.documents,
      total: response.total
    });
  } catch (error) {
    console.error('💥 [API] Erro ao listar carrinhos:', error);
    return NextResponse.json(
      { success: false, error: 'Erro ao carregar carrinhos' },
      { status: 500 }
    );
  }
}

export async function POST(request: NextRequest) {
  console.log(' [API] Criando novo carrinho...');

  try {
    const body = await request.json();
    console.log('📤 [API] Dados recebidos:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CARRINHOS_ID!}/documents`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    const data = await response.json();

    if (response.status === 201 || response.status === 409) {
      console.log('✅ [API] Carrinho criado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      console.error('❌ [API] Erro ao criar:', response.status, data);
      return NextResponse.json(
        { success: false, error: 'Erro ao criar carrinho', details: data },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na criação:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/catalogo-produtos/[id]/route.ts

import { NextResponse, unstable_rootParams } from 'next/server';

export const runtime = 'edge';

export async function PATCH(request: Request) {
  const { id } = await unstable_rootParams();
  console.log('🔄 [API] Atualizando item do catálogo:', id);

  try {
    const body = await request.json();
    console.log('📤 [API] Dados para atualização:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CATALOGO_PRODUTOS_ID!}/documents/${id}`,
      {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    if (response.ok) {
      const data = await response.json();
      console.log('✅ [API] Item do catálogo atualizado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao atualizar:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao atualizar produto', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na atualização:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}

export async function DELETE() {
  const { id } = await unstable_rootParams();
  console.log('🗑️ [API] Excluindo item do catálogo:', id);

  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CATALOGO_PRODUTOS_ID!}/documents/${id}`,
      {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        }
      }
    );

    if (response.ok || response.status === 204) {
      console.log('✅ [API] Item do catálogo excluído com sucesso!');
      return NextResponse.json({ success: true });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao excluir:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao excluir produto', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na exclusão:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/catalogo-produtos/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { Client, Databases, Query } from 'node-appwrite';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  console.log('📋 [API] Listando catálogo de produtos...');

  try {
    const apiKey = process.env.APPWRITE_API_KEY;
    if (!apiKey) {
      console.error('❌ [API] APPWRITE_API_KEY não configurada');
      return NextResponse.json(
        { success: false, error: 'Configuração do servidor ausente' },
        { status: 500 }
      );
    }

    const endpoint = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!;
    const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!;
    const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
    const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CATALOGO_PRODUTOS_ID!;

    const { searchParams } = new URL(request.url);
    const limit = Number(searchParams.get('limit')) || 10;
    const page = Number(searchParams.get('page')) || 1;
    const termoBuscado = searchParams.get('termoBuscado') || '';
    const offset = (page - 1) * limit;

    const client = new Client()
      .setEndpoint(endpoint)
      .setProject(projectId)
      .setKey(apiKey);

    const databases = new Databases(client);

    const queries = [
      Query.limit(limit),
      Query.offset(offset)
    ];

    if (termoBuscado) {
      queries.unshift(Query.search('nome', termoBuscado));
    }

    const response = await databases.listDocuments(databaseId, collectionId, queries);

    console.log(`✅ [API] ${response.total} itens do catálogo carregados!`);
    console.log('📦 [API] Dados retornados:', JSON.stringify(response, null, 2));
    return NextResponse.json({
      success: true,
      documents: response.documents,
      total: response.total
    });
  } catch (error) {
    console.error('💥 [API] Erro ao listar produtos:', error);
    return NextResponse.json(
      { success: false, error: 'Erro ao carregar produtos' },
      { status: 500 }
    );
  }
}

export async function POST(request: NextRequest) {
  console.log(' [API] Criando novo item no catálogo...');

  try {
    const body = await request.json();
    console.log('📤 [API] Dados recebidos:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CATALOGO_PRODUTOS_ID!}/documents`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    const data = await response.json();

    if (response.status === 201 || response.status === 409) {
      console.log('✅ [API] Item do catálogo criado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      console.error('❌ [API] Erro ao criar:', response.status, data);
      return NextResponse.json(
        { success: false, error: 'Erro ao criar item do catálogo', details: data },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na criação:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/categorias/[id]/route.ts

import { NextResponse, unstable_rootParams } from 'next/server';

export const runtime = 'edge';

// 🔄 PATCH - Atualizar categoria
export async function PATCH(request: Request) {
  const { id } = await unstable_rootParams();
  console.log('🔄 [API] Atualizando categoria:', id);

  try {
    const body = await request.json();
    console.log('📤 [API] Dados para atualização:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CATEGORIAS_ID!}/documents/${id}`,
      {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    if (response.ok) {
      const data = await response.json();
      console.log('✅ [API] Categoria atualizado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao atualizar:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao atualizar categoria', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na atualização:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}

// 🗑️ DELETE - Excluir categoria
export async function DELETE() {
  const { id } = await unstable_rootParams();
  console.log('🗑️ [API] Excluindo categoria:', id);

  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CATEGORIAS_ID!}/documents/${id}`,
      {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        }
      }
    );

    if (response.ok || response.status === 204) {
      console.log('✅ [API] Categoria excluído com sucesso!');
      return NextResponse.json({ success: true });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao excluir:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao excluir categoria', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na exclusão:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/categorias/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { Client, Databases, Query } from 'node-appwrite';

export const runtime = 'edge';

// 🔍 GET - Listar categorias
export async function GET(request: NextRequest) {
  console.log('📋 [API] Listando categorias...');

  try {
    const apiKey = process.env.APPWRITE_API_KEY;
    if (!apiKey) {
      console.error('❌ [API] APPWRITE_API_KEY não configurada');
      return NextResponse.json(
        { success: false, error: 'Configuração do servidor ausente' },
        { status: 500 }
      );
    }

    const endpoint = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!;
    const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!;
    const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
    const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CATEGORIAS_ID!;

    const { searchParams } = new URL(request.url);
    const limit = Number(searchParams.get('limit')) || 10;
    const page = Number(searchParams.get('page')) || 1;
    const termoBuscado = searchParams.get('termoBuscado') || '';
    const offset = (page - 1) * limit;

    const client = new Client()
      .setEndpoint(endpoint)
      .setProject(projectId)
      .setKey(apiKey);

    const databases = new Databases(client);

    const queries = [
      Query.limit(limit),
      Query.offset(offset)
    ];

    if (termoBuscado) {
      queries.unshift(Query.search('nome', termoBuscado));
    }

    const response = await databases.listDocuments(databaseId, collectionId, queries);

    console.log(`✅ [API] ${response.total} categorias carregados!`);
    return NextResponse.json({
      success: true,
      documents: response.documents,
      total: response.total
    });
  } catch (error) {
    console.error('💥 [API] Erro ao listar categorias:', error);
    return NextResponse.json(
      { success: false, error: 'Erro ao carregar categorias' },
      { status: 500 }
    );
  }
}

//  POST - Criar categorias
export async function POST(request: NextRequest) {
  console.log(' [API] Criando novo categorias...');

  try {
    const body = await request.json();
    console.log('📤 [API] Dados recebidos:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CATEGORIAS_ID!}/documents`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    const data = await response.json();

    if (response.status === 201 || response.status === 409) {
      console.log('✅ [API] Categoria criado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      console.error('❌ [API] Erro ao criar:', response.status, data);
      return NextResponse.json(
        { success: false, error: 'Erro ao criar categorias', details: data },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na criação:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/empresas/[id]/route.ts

import { NextResponse, unstable_rootParams } from 'next/server';

export const runtime = 'edge';

// 🔄 PATCH - Atualizar empresa
export async function PATCH(request: Request) {
  const { id } = await unstable_rootParams();
  console.log('🔄 [API] Atualizando empresa:', id);
  
  try {
    const body = await request.json();
    console.log('📤 [API] Dados para atualização:', body);
    
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_EMPRESAS_ID!}/documents/${id}`,
      {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );
    
    if (response.ok) {
      const data = await response.json();
      console.log('✅ [API] Empresa atualizada com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao atualizar:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao atualizar empresa', details: errorData },
        { status: response.status }
      );
    }
    
  } catch (error) {
    console.error('💥 [API] Erro na atualização:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}

// 🗑️ DELETE - Excluir empresa
export async function DELETE() {
  const { id } = await unstable_rootParams();
  console.log('🗑️ [API] Excluindo empresa:', id);
  
  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_EMPRESAS_ID!}/documents/${id}`,
      {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        }
      }
    );
    
    if (response.ok || response.status === 204) {
      console.log('✅ [API] Empresa excluída com sucesso!');
      return NextResponse.json({ success: true });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao excluir:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao excluir empresa', details: errorData },
        { status: response.status }
      );
    }
    
  } catch (error) {
    console.error('💥 [API] Erro na exclusão:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/empresas/route.ts

import { NextRequest, NextResponse } from 'next/server';

export const runtime = 'edge';

// 🔍 GET - Listar empresas
export async function GET() {
  console.log('📋 [API] Listando empresas...');

  try {
    const apiKey = process.env.APPWRITE_API_KEY;
    if (!apiKey) {
      console.error('❌ [API] APPWRITE_API_KEY não configurada');
      return NextResponse.json(
        { success: false, error: 'Configuração do servidor ausente' },
        { status: 500 }
      );
    }

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_EMPRESAS_ID!}/documents`,
      {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': apiKey
        }
      }
    );

    const data = await response.json().catch(() => ({}));

    if (response.ok) {
      console.log(`✅ [API] ${data.total} empresas carregadas!`);
      return NextResponse.json({
        success: true,
        documents: data.documents,
        total: data.total
      });
    }

    console.error('❌ [API] Erro ao listar:', response.status, data);
    return NextResponse.json(
      { success: false, error: 'Erro ao carregar empresas', details: data },
      { status: response.status }
    );

  } catch (error) {
    console.error('💥 [API] Erro ao listar:', error);
    return NextResponse.json(
      { success: false, error: 'Erro ao carregar empresas' },
      { status: 500 }
    );
  }
}

//  POST - Criar empresa
export async function POST(request: NextRequest) {
  console.log(' [API] Criando nova empresa...');
  
  try {
    const body = await request.json();
    console.log('📤 [API] Dados recebidos:', body);
    
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_EMPRESAS_ID!}/documents`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );
    
    const data = await response.json();
    
    if (response.status === 201 || response.status === 409) {
      console.log('✅ [API] Empresa criada com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      console.error('❌ [API] Erro ao criar:', response.status, data);
      return NextResponse.json(
        { success: false, error: 'Erro ao criar empresa', details: data },
        { status: response.status }
      );
    }
    
  } catch (error) {
    console.error('💥 [API] Erro na criação:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}

src/app/api/enderecos/[id]/route.ts

import { NextResponse, unstable_rootParams } from 'next/server';

export const runtime = 'edge';

export async function PATCH(request: Request) {
  const { id } = await unstable_rootParams();
  console.log('🔄 [API] Atualizando endereço:', id);

  try {
    const body = await request.json();
    console.log('📤 [API] Dados para atualização:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_ENDERECOS_ID!}/documents/${id}`,
      {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    if (response.ok) {
      const data = await response.json();
      console.log('✅ [API] Endereço atualizado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao atualizar:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao atualizar endereço', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na atualização:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}

export async function DELETE() {
  const { id } = await unstable_rootParams();
  console.log('🗑️ [API] Excluindo endereço:', id);

  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_ENDERECOS_ID!}/documents/${id}`,
      {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        }
      }
    );

    if (response.ok || response.status === 204) {
      console.log('✅ [API] Endereço excluído com sucesso!');
      return NextResponse.json({ success: true });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao excluir:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao excluir endereço', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na exclusão:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/enderecos/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { Client, Databases, Query } from 'node-appwrite';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  console.log('📋 [API] Listando endereços...');

  try {
    const apiKey = process.env.APPWRITE_API_KEY;
    if (!apiKey) {
      console.error('❌ [API] APPWRITE_API_KEY não configurada');
      return NextResponse.json(
        { success: false, error: 'Configuração do servidor ausente' },
        { status: 500 }
      );
    }

    const endpoint = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!;
    const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!;
    const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
    const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_ENDERECOS_ID!;

    const { searchParams } = new URL(request.url);
    const limit = Number(searchParams.get('limit')) || 10;
    const page = Number(searchParams.get('page')) || 1;
    const termoBuscado = searchParams.get('termoBuscado') || '';
    const offset = (page - 1) * limit;

    const client = new Client()
      .setEndpoint(endpoint)
      .setProject(projectId)
      .setKey(apiKey);

    const databases = new Databases(client);

    const queries = [
      Query.or([
        Query.search('titulo', termoBuscado),
        Query.search('cep', termoBuscado),
        Query.search('cidade', termoBuscado)
      ]),
      Query.limit(limit),
      Query.offset(offset)
    ];

    const response = await databases.listDocuments(databaseId, collectionId, queries);

    console.log(`✅ [API] ${response.total} endereços carregados!`);
    return NextResponse.json({
      success: true,
      documents: response.documents,
      total: response.total
    });
  } catch (error) {
    console.error('💥 [API] Erro ao listar endereços:', error);
    return NextResponse.json(
      { success: false, error: 'Erro ao carregar endereços' },
      { status: 500 }
    );
  }
}

export async function POST(request: NextRequest) {
  console.log(' [API] Criando novo endereço...');

  try {
    const body = await request.json();
    console.log('📤 [API] Dados recebidos:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_ENDERECOS_ID!}/documents`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    const data = await response.json();

    if (response.status === 201 || response.status === 409) {
      console.log('✅ [API] Endereço criado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      console.error('❌ [API] Erro ao criar:', response.status, data);
      return NextResponse.json(
        { success: false, error: 'Erro ao criar endereço', details: data },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na criação:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/faturas/[id]/route.ts

import { NextResponse, unstable_rootParams } from 'next/server';

export const runtime = 'edge';

export async function PATCH(request: Request) {
  const { id } = await unstable_rootParams();
  try {
    const body = await request.json();
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_FATURAS_ID!}/documents/${id}`,
      {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    if (response.ok) {
      const data = await response.json();
      return NextResponse.json({ success: true, data });
    } else {
      const errorData = await response.json().catch(() => ({}));
      return NextResponse.json(
        { success: false, error: 'Erro ao atualizar fatura', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('Erro na atualização da fatura:', error);
    return NextResponse.json({ success: false, error: 'Erro interno do servidor' }, { status: 500 });
  }
}

export async function DELETE() {
  const { id } = await unstable_rootParams();
  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_FATURAS_ID!}/documents/${id}`,
      {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        }
      }
    );

    if (response.ok || response.status === 204) {
      return NextResponse.json({ success: true });
    } else {
      const errorData = await response.json().catch(() => ({}));
      return NextResponse.json(
        { success: false, error: 'Erro ao excluir fatura', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('Erro na exclusão da fatura:', error);
    return NextResponse.json({ success: false, error: 'Erro interno do servidor' }, { status: 500 });
  }
}


src/app/api/faturas/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { Client, Databases, Query } from 'node-appwrite';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  try {
    const apiKey = process.env.APPWRITE_API_KEY;
    if (!apiKey) {
      return NextResponse.json({ success: false, error: 'Configuração do servidor ausente' }, { status: 500 });
    }

    const endpoint = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!;
    const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!;
    const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
    const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_FATURAS_ID!;

    const { searchParams } = new URL(request.url);
    const limit = Number(searchParams.get('limit')) || 10;
    const page = Number(searchParams.get('page')) || 1;
    const termoBuscado = searchParams.get('termoBuscado') || '';
    const offset = (page - 1) * limit;

    const client = new Client().setEndpoint(endpoint).setProject(projectId).setKey(apiKey);
    const databases = new Databases(client);

    const queries = [Query.search('empresas', termoBuscado), Query.limit(limit), Query.offset(offset)];
    const response = await databases.listDocuments(databaseId, collectionId, queries);

    return NextResponse.json({ success: true, documents: response.documents, total: response.total });
  } catch (error) {
    console.error('Erro ao listar faturas:', error);
    return NextResponse.json({ success: false, error: 'Erro ao carregar faturas' }, { status: 500 });
  }
}

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_FATURAS_ID!}/documents`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    const data = await response.json();

    if (response.status === 201 || response.status === 409) {
      return NextResponse.json({ success: true, data });
    }

    return NextResponse.json(
      { success: false, error: 'Erro ao criar fatura', details: data },
      { status: response.status }
    );
  } catch (error) {
    console.error('Erro na criação da fatura:', error);
    return NextResponse.json({ success: false, error: 'Erro interno do servidor' }, { status: 500 });
  }
}


src/app/api/laboratorios/[id]/route.ts

import { NextResponse, unstable_rootParams } from 'next/server';

export const runtime = 'edge';

// 🔄 PATCH - Atualizar laboratório
export async function PATCH(request: Request) {
  const { id } = await unstable_rootParams();
  console.log('🔄 [API] Atualizando laboratório:', id);

  try {
    const body = await request.json();
    console.log('📤 [API] Dados para atualização:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_LABORATORIOS_ID!}/documents/${id}`,
      {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    if (response.ok) {
      const data = await response.json();
      console.log('✅ [API] Laboratório atualizado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao atualizar:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao atualizar laboratório', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na atualização:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}

// 🗑️ DELETE - Excluir laboratório
export async function DELETE() {
  const { id } = await unstable_rootParams();
  console.log('🗑️ [API] Excluindo laboratório:', id);

  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_LABORATORIOS_ID!}/documents/${id}`,
      {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        }
      }
    );

    if (response.ok || response.status === 204) {
      console.log('✅ [API] Laboratório excluído com sucesso!');
      return NextResponse.json({ success: true });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao excluir:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao excluir laboratório', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na exclusão:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/laboratorios/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { Client, Databases, Query } from 'node-appwrite';

export const runtime = 'edge';

// 🔍 GET - Listar laboratórios
export async function GET(request: NextRequest) {
  console.log('📋 [API] Listando laboratórios...');

  try {
    const apiKey = process.env.APPWRITE_API_KEY;
    if (!apiKey) {
      console.error('❌ [API] APPWRITE_API_KEY não configurada');
      return NextResponse.json(
        { success: false, error: 'Configuração do servidor ausente' },
        { status: 500 }
      );
    }

    const endpoint = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!;
    const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!;
    const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
    const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_LABORATORIOS_ID!;

    const { searchParams } = new URL(request.url);
    const limit = Number(searchParams.get('limit')) || 10;
    const page = Number(searchParams.get('page')) || 1;
    const termoBuscado = searchParams.get('termoBuscado') || '';
    const offset = (page - 1) * limit;

    const client = new Client()
      .setEndpoint(endpoint)
      .setProject(projectId)
      .setKey(apiKey);

    const databases = new Databases(client);

    const queries = [
      Query.search('nome', termoBuscado),
      Query.limit(limit),
      Query.offset(offset)
    ];

    const response = await databases.listDocuments(databaseId, collectionId, queries);

    console.log(`✅ [API] ${response.total} laboratórios carregados!`);
    return NextResponse.json({
      success: true,
      documents: response.documents,
      total: response.total
    });
  } catch (error) {
    console.error('💥 [API] Erro ao listar laboratórios:', error);
    return NextResponse.json(
      { success: false, error: 'Erro ao carregar laboratórios' },
      { status: 500 }
    );
  }
}

//  POST - Criar laboratório
export async function POST(request: NextRequest) {
  console.log(' [API] Criando novo laboratório...');

  try {
    const body = await request.json();
    console.log('📤 [API] Dados recebidos:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_LABORATORIOS_ID!}/documents`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    const data = await response.json();

    if (response.status === 201 || response.status === 409) {
      console.log('✅ [API] Laboratório criado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      console.error('❌ [API] Erro ao criar:', response.status, data);
      return NextResponse.json(
        { success: false, error: 'Erro ao criar laboratório', details: data },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na criação:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/pagamentos/[id]/route.ts

import { NextResponse, unstable_rootParams } from 'next/server';

export const runtime = 'edge';

export async function PUT(request: Request) {
  const { id } = await unstable_rootParams();

  try {
    const body = await request.json();

    const response = await fetch(`${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PAGAMENTOS_ID!}/documents/${id}`, {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json',
        'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
        'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
      },
      body: JSON.stringify(body)
    });

    if (response.ok) {
      const data = await response.json();
      return NextResponse.json({ success: true, data });
    } else {
      const errorData = await response.json().catch(() => ({}));
      return NextResponse.json(
        { success: false, error: 'Erro ao atualizar pagamento', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}

export async function DELETE() {
  const { id } = await unstable_rootParams();

  try {
    const response = await fetch(`${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PAGAMENTOS_ID!}/documents/${id}`, {
      method: 'DELETE',
      headers: {
        'Content-Type': 'application/json',
        'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
        'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
      }
    });

    if (response.ok || response.status === 204) {
      return NextResponse.json({ success: true });
    } else {
      const errorData = await response.json().catch(() => ({}));
      return NextResponse.json(
        { success: false, error: 'Erro ao excluir pagamento', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/pagamentos/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { Client, Databases, Query } from 'node-appwrite';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  try {
    const apiKey = process.env.APPWRITE_API_KEY;
    if (!apiKey) {
      return NextResponse.json(
        { success: false, error: 'Configuração do servidor ausente' },
        { status: 500 }
      );
    }

    const endpoint = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!;
    const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!;
    const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
    const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PAGAMENTOS_ID!;

    const { searchParams } = new URL(request.url);
    const limit = Number(searchParams.get('limit')) || 10;
    const page = Number(searchParams.get('page')) || 1;
    const search = searchParams.get('search') || '';
    const offset = (page - 1) * limit;

    const client = new Client().setEndpoint(endpoint).setProject(projectId).setKey(apiKey);
    const databases = new Databases(client);

    const queries = [Query.limit(limit), Query.offset(offset)];
    if (search) queries.push(Query.search('status', search));

    const response = await databases.listDocuments(
      databaseId,
      collectionId,
      queries
    );

    return NextResponse.json({
      success: true,
      documents: response.documents,
      total: response.total
    });
  } catch (error) {
    return NextResponse.json(
      { success: false, error: 'Erro ao carregar pagamentos' },
      { status: 500 }
    );
  }
}

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();

    const response = await fetch(`${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PAGAMENTOS_ID!}/documents`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
        'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
      },
      body: JSON.stringify(body)
    });

    const data = await response.json();

    if (response.status === 201 || response.status === 409) {
      return NextResponse.json({ success: true, data });
    } else {
      return NextResponse.json(
        { success: false, error: 'Erro ao criar pagamento', details: data },
        { status: response.status }
      );
    }
  } catch (error) {
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/pedidos/[id]/route.ts

import { NextResponse, unstable_rootParams } from 'next/server';

export const runtime = 'edge';

export async function PATCH(request: Request) {
  const { id } = await unstable_rootParams();
  try {
    const body = await request.json();
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PEDIDOS_ID!}/documents/${id}`,
      {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!,
        },
        body: JSON.stringify(body),
      }
    );

    if (response.ok) {
      const data = await response.json();
      return NextResponse.json({ success: true, data });
    } else {
      const errorData = await response.json().catch(() => ({}));
      return NextResponse.json(
        { success: false, error: 'Erro ao atualizar pedido', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    return NextResponse.json({ success: false, error: 'Erro interno do servidor' }, { status: 500 });
  }
}

export async function DELETE() {
  const { id } = await unstable_rootParams();
  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PEDIDOS_ID!}/documents/${id}`,
      {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!,
        },
      }
    );

    if (response.ok || response.status === 204) {
      return NextResponse.json({ success: true });
    } else {
      const errorData = await response.json().catch(() => ({}));
      return NextResponse.json(
        { success: false, error: 'Erro ao excluir pedido', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    return NextResponse.json({ success: false, error: 'Erro interno do servidor' }, { status: 500 });
  }
}


src/app/api/pedidos/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { Client, Databases, Query } from 'node-appwrite';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  try {
    const apiKey = process.env.APPWRITE_API_KEY;
    if (!apiKey) {
      return NextResponse.json(
        { success: false, error: 'Configuração do servidor ausente' },
        { status: 500 }
      );
    }

    const endpoint = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!;
    const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!;
    const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
    const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PEDIDOS_ID!;

    const { searchParams } = new URL(request.url);
    const limit = Number(searchParams.get('limit')) || 10;
    const page = Number(searchParams.get('page')) || 1;
    const status = searchParams.get('status') || '';
    const search = searchParams.get('search') || '';
    const offset = (page - 1) * limit;

    const client = new Client().setEndpoint(endpoint).setProject(projectId).setKey(apiKey);
    const databases = new Databases(client);

    const queries = [Query.limit(limit), Query.offset(offset)];
    if (status) queries.push(Query.equal('status', status));
    if (search) queries.push(Query.search('comprador', search));

    const response = await databases.listDocuments(databaseId, collectionId, queries);

    return NextResponse.json({ success: true, documents: response.documents, total: response.total });
  } catch (error) {
    return NextResponse.json({ success: false, error: 'Erro ao carregar pedidos' }, { status: 500 });
  }
}

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PEDIDOS_ID!}/documents`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!,
        },
        body: JSON.stringify(body),
      }
    );

    const data = await response.json();

    if (response.status === 201 || response.status === 409) {
      return NextResponse.json({ success: true, data });
    }
    return NextResponse.json(
      { success: false, error: 'Erro ao criar pedido', details: data },
      { status: response.status }
    );
  } catch (error) {
    return NextResponse.json({ success: false, error: 'Erro interno do servidor' }, { status: 500 });
  }
}


src/app/api/produtos/[id]/route.ts

import { NextResponse, unstable_rootParams } from 'next/server';

export const runtime = 'edge';

export async function PATCH(request: Request) {
  const { id } = await unstable_rootParams();
  console.log('🔄 [API] Atualizando produto:', id);

  try {
    const body = await request.json();
    console.log('📤 [API] Dados para atualização:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PRODUTOS_ID!}/documents/${id}`,
      {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    if (response.ok) {
      const data = await response.json();
      console.log('✅ [API] Produto atualizado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao atualizar:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao atualizar produto', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na atualização:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}

export async function DELETE() {
  const { id } = await unstable_rootParams();
  console.log('🗑️ [API] Excluindo produto:', id);

  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PRODUTOS_ID!}/documents/${id}`,
      {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        }
      }
    );

    if (response.ok || response.status === 204) {
      console.log('✅ [API] Produto excluído com sucesso!');
      return NextResponse.json({ success: true });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao excluir:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao excluir produto', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na exclusão:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/produtos/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { Client, Databases, Query } from 'node-appwrite';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  console.log('📋 [API] Listando produtos...');

  try {
    const apiKey = process.env.APPWRITE_API_KEY;
    if (!apiKey) {
      console.error('❌ [API] APPWRITE_API_KEY não configurada');
      return NextResponse.json(
        { success: false, error: 'Configuração do servidor ausente' },
        { status: 500 }
      );
    }

    const endpoint = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!;
    const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!;
    const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
    const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PRODUTOS_ID!;

    const { searchParams } = new URL(request.url);
    const limit = Number(searchParams.get('limit')) || 10;
    const page = Number(searchParams.get('page')) || 1;
    const termoBuscado = searchParams.get('termoBuscado') || '';
    const offset = (page - 1) * limit;

    const client = new Client()
      .setEndpoint(endpoint)
      .setProject(projectId)
      .setKey(apiKey);

    const databases = new Databases(client);

    const queries = [
      Query.limit(limit),
      Query.offset(offset)
    ];

    if (termoBuscado) {
      queries.unshift(Query.search('nome', termoBuscado));
    }

    const response = await databases.listDocuments(databaseId, collectionId, queries);

    const catalogCollectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_CATALOGO_PRODUTOS_ID!;

    const populatedDocuments = await Promise.all(
      response.documents.map(async (doc) => {
        try {
          const catalogId = doc['catalogo-produto-id'];
          if (catalogId) {
            const catalog = await databases.getDocument(databaseId, catalogCollectionId, catalogId);
            return { ...doc, 'catalogo-produtos': catalog };
          }
        } catch {
          // ignore individual fetch errors
        }
        return { ...doc };
      })
    );

    console.log(`✅ [API] ${response.total} produtos carregados!`);
    console.log('📦 [API] Dados retornados:', JSON.stringify(populatedDocuments, null, 2));
    return NextResponse.json({
      success: true,
      documents: populatedDocuments,
      total: response.total
    });
  } catch (error) {
    console.error('💥 [API] Erro ao listar produtos:', error);
    return NextResponse.json(
      { success: false, error: 'Erro ao carregar produtos' },
      { status: 500 }
    );
  }
}

export async function POST(request: NextRequest) {
  console.log(' [API] Criando novo produto...');

  try {
    const body = await request.json();
    console.log('📤 [API] Dados recebidos:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PRODUTOS_ID!}/documents`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        },
        body: JSON.stringify(body)
      }
    );

    const data = await response.json();

    if (response.status === 201 || response.status === 409) {
      console.log('✅ [API] Produto criado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      console.error('❌ [API] Erro ao criar:', response.status, data);
      return NextResponse.json(
        { success: false, error: 'Erro ao criar produto', details: data },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na criação:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/user/permissions/route.ts

import { NextResponse } from 'next/server';

export const runtime = 'edge';

// 🔐 GET - Verificar permissões do usuário
export async function GET() {
  console.log('🔐 [API] Verificando permissões do usuário...');
  
  try {
    // 🧪 Teste de permissões com a API Key
    const testResponse = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_EMPRESAS_ID!}/documents?limit=1`,
      {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!
        }
      }
    );
    
    const permissions = {
      apiKeyValid: testResponse.ok,
      canRead: testResponse.ok,
      canWrite: testResponse.ok,
      canUpdate: testResponse.ok,
      canDelete: testResponse.ok,
      apiKeyType: 'Server API Key',
      project: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
      database: process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!,
      collection: process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_EMPRESAS_ID!,
      status: testResponse.status,
      timestamp: new Date().toISOString()
    };
    
    console.log('✅ [API] Permissões verificadas:', permissions);
    
    return NextResponse.json({
      success: true,
      permissions
    });
    
  } catch (error) {
    console.error('💥 [API] Erro ao verificar permissões:', error);
    return NextResponse.json(
      { success: false, error: 'Erro ao verificar permissões' },
      { status: 500 }
    );
  }
}

src/app/api/usuarios/[id]/route.ts

import { NextResponse, unstable_rootParams } from 'next/server';

export const runtime = 'edge';

export async function PATCH(request: Request) {
  const { id } = await unstable_rootParams();
  console.log('🔄 [API] Atualizando usuário:', id);

  try {
    const body = await request.json();
    console.log('📤 [API] Dados para atualização:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_USUARIOS_ID!}/documents/${id}`,
      {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!,
        },
        body: JSON.stringify(body),
      }
    );

    if (response.ok) {
      const data = await response.json();
      console.log('✅ [API] Usuário atualizado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao atualizar:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao atualizar usuário', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na atualização:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}

export async function DELETE() {
  const { id } = await unstable_rootParams();
  console.log('🗑️ [API] Excluindo usuário:', id);

  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_USUARIOS_ID!}/documents/${id}`,
      {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!,
        },
      }
    );

    if (response.ok || response.status === 204) {
      console.log('✅ [API] Usuário excluído com sucesso!');
      return NextResponse.json({ success: true });
    } else {
      const errorData = await response.json().catch(() => ({}));
      console.error('❌ [API] Erro ao excluir:', response.status, errorData);
      return NextResponse.json(
        { success: false, error: 'Erro ao excluir usuário', details: errorData },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na exclusão:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/api/usuarios/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { Client, Databases, Query } from 'node-appwrite';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  console.log('📋 [API] Listando usuários...');

  try {
    const apiKey = process.env.APPWRITE_API_KEY;
    if (!apiKey) {
      console.error('❌ [API] APPWRITE_API_KEY não configurada');
      return NextResponse.json(
        { success: false, error: 'Configuração do servidor ausente' },
        { status: 500 }
      );
    }

    const endpoint = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!;
    const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!;
    const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
    const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_USUARIOS_ID!;

    const { searchParams } = new URL(request.url);
    const limit = Number(searchParams.get('limit')) || 10;
    const page = Number(searchParams.get('page')) || 1;
    const termoBuscado = searchParams.get('termoBuscado') || '';
    const offset = (page - 1) * limit;

    const client = new Client()
      .setEndpoint(endpoint)
      .setProject(projectId)
      .setKey(apiKey);

    const databases = new Databases(client);

    const queries = [
      Query.search('nome-civil', termoBuscado),
      Query.limit(limit),
      Query.offset(offset),
    ];

    const response = await databases.listDocuments(databaseId, collectionId, queries);

    console.log(`✅ [API] ${response.total} usuários carregados!`);
    return NextResponse.json({
      success: true,
      documents: response.documents,
      total: response.total,
    });
  } catch (error) {
    console.error('💥 [API] Erro ao listar usuários:', error);
    return NextResponse.json(
      { success: false, error: 'Erro ao carregar usuários' },
      { status: 500 }
    );
  }
}

export async function POST(request: NextRequest) {
  console.log(' [API] Criando novo usuário...');

  try {
    const body = await request.json();
    console.log('📤 [API] Dados recebidos:', body);

    const response = await fetch(
      `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!}/databases/${process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!}/collections/${process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_USUARIOS_ID!}/documents`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Appwrite-Project': process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!,
          'X-Appwrite-Key': process.env.APPWRITE_API_KEY!,
        },
        body: JSON.stringify(body),
      }
    );

    const data = await response.json();

    if (response.status === 201 || response.status === 409) {
      console.log('✅ [API] Usuário criado com sucesso!');
      return NextResponse.json({ success: true, data });
    } else {
      console.error('❌ [API] Erro ao criar:', response.status, data);
      return NextResponse.json(
        { success: false, error: 'Erro ao criar usuário', details: data },
        { status: response.status }
      );
    }
  } catch (error) {
    console.error('💥 [API] Erro na criação:', error);
    return NextResponse.json(
      { success: false, error: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}


src/app/caju/page.tsx

'use client';
import { useEffect, useState } from 'react';
import { functions } from '@/lib/appwrite';

export default function CajuFunctionPage() {
  const [output, setOutput] = useState<string>('Executando…');

  useEffect(() => {
    (async () => {
      try {
        const exec = await functions.createExecution(
          process.env.NEXT_PUBLIC_APPWRITE_FUNCTION_CAJU_ID as string,
          '',
          false
        );
        setOutput(exec.responseBody || '⚠️ Sem resposta');
      } catch (err: any) {
        setOutput(err?.message ?? 'Erro desconhecido');
      }
    })();
  }, []);

  return (
    <main className="p-6 max-w-3xl mx-auto">
      <h1 className="text-2xl font-semibold mb-4">Função Caju</h1>
      <pre className="bg-gray-800 text-green-400 rounded p-4 whitespace-pre-wrap break-words">
        {output}
      </pre>
    </main>
  );
}


src/app/carrinhos/page.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import CarrinhoForm from '@/components/CarrinhoForm';
import CarrinhoList from '@/components/CarrinhoList';
import { useCarrinhos, CarrinhoFormData } from '@/hooks/useCarrinhos';

const GestaoCarrinhos = () => {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [editing, setEditing] = useState<Models.Document | null>(null);
  const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
  const [searchTerm, setSearchTerm] = useState('');

  const {
    carrinhos,
    loading,
    error,
    totalCarrinhos,
    currentPage,
    listarCarrinhos,
    buscarCarrinhos,
    cadastrarCarrinho,
    atualizarCarrinho,
    deletarCarrinho,
    setCurrentPage
  } = useCarrinhos();

  useEffect(() => {
    const initializeUser = async () => {
      try {
        const currentUser = await account.get();
        setUser(currentUser);

        if (activeTab === 'lista') {
          await listarCarrinhos();
        }
      } catch (error) {
        console.error('❌ Usuário não autenticado:', error);
        router.push('/');
      }
    };

    initializeUser();
  }, [activeTab, router, listarCarrinhos]);

  const handleFormSubmit = async (formData: CarrinhoFormData): Promise<boolean> => {
    if (editing) {
      const success = await atualizarCarrinho(editing.$id, formData);
      if (success) {
        setEditing(null);
        setActiveTab('lista');
      }
      return success;
    } else {
      const success = await cadastrarCarrinho(formData);
      if (success) {
        setTimeout(() => setActiveTab('lista'), 2000);
      }
      return success;
    }
  };

  const handleEdit = (car: Models.Document) => {
    setEditing(car);
    setActiveTab('cadastro');
  };

  const handleCancelEdit = () => {
    setEditing(null);
    setActiveTab('lista');
  };

  const handlePrevPage = async () => {
    if (currentPage > 1) {
      if (searchTerm.trim()) {
        await buscarCarrinhos(searchTerm, currentPage - 1);
      } else {
        await listarCarrinhos(currentPage - 1);
      }
    }
  };

  const handleSearch = async (term: string) => {
    setSearchTerm(term);
    if (term.trim()) {
      await buscarCarrinhos(term, 1);
    } else {
      await listarCarrinhos(1);
    }
  };

  const handleNextPage = async () => {
    const totalPages = Math.ceil(totalCarrinhos / 10);
    if (currentPage < totalPages) {
      if (searchTerm.trim()) {
        await buscarCarrinhos(searchTerm, currentPage + 1);
      } else {
        await listarCarrinhos(currentPage + 1);
      }
    }
  };

  if (!user) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
          <p className="text-gray-600">Verificando autenticação...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header
        user={user}
        title="Gestão de Carrinhos"
        subtitle="Gerencie os carrinhos da plataforma SaveInMed"
      />

      <main className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        <div className="mb-6">
          <nav className="flex space-x-8 bg-white p-4 rounded-lg shadow-sm">
            <button
              onClick={() => {
                setActiveTab('lista');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'lista'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
              📋 Listar Carrinhos
            </button>
            <button
              onClick={() => {
                setActiveTab('cadastro');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'cadastro'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
               Cadastrar Carrinho
            </button>
          </nav>
        </div>

        {activeTab === 'lista' && (
          <CarrinhoList
            carrinhos={carrinhos}
            loading={loading}
            error={error}
            totalCarrinhos={totalCarrinhos}
            currentPage={currentPage}
            pageSize={10}
            onEdit={handleEdit}
            onDelete={deletarCarrinho}
            onRefresh={() =>
              searchTerm.trim()
                ? buscarCarrinhos(searchTerm, currentPage)
                : listarCarrinhos(currentPage)
            }
            onPrevPage={handlePrevPage}
            onNextPage={handleNextPage}
            onSearch={handleSearch}
          />
        )}

        {activeTab === 'cadastro' && (
          <CarrinhoForm
            onSubmit={handleFormSubmit}
            onCancel={editing ? handleCancelEdit : undefined}
            initialData={editing}
            loading={loading}
          />
        )}
      </main>
    </div>
  );
};

export default GestaoCarrinhos;


src/app/catalogo-produtos/page.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import CatalogoProdutoForm from '@/components/CatalogoProdutoForm';
import CatalogoProdutosList from '@/components/CatalogoProdutosList';
import { useCatalogoProdutos, CatalogoProdutoFormData } from '@/hooks/useCatalogoProdutos';

const GestaoCatalogoProdutos = () => {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [editing, setEditing] = useState<Models.Document | null>(null);
  const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
  const [searchTerm, setSearchTerm] = useState('');
  
  const {
    catalogoProdutos,
    loading,
    error,
    totalCatalogoProdutos,
    currentPage,
    listarCatalogo,
    buscarCatalogo,
    cadastrarCatalogo,
    atualizarCatalogo,
    deletarCatalogo,
    setCurrentPage
  } = useCatalogoProdutos();

  // 🔐 Verificar autenticação
  useEffect(() => {
    const initializeUser = async () => {
      try {
        const currentUser = await account.get();
        setUser(currentUser);
        
        if (activeTab === 'lista') {
          await listarCatalogo();
        }
      } catch (error) {
        console.error('❌ Usuário não autenticado:', error);
        router.push('/');
      }
    };

    initializeUser();
  }, [activeTab, router, listarCatalogo]);

  const handleFormSubmit = async (formData: CatalogoProdutoFormData): Promise<boolean> => {
    if (editing) {
      const success = await atualizarCatalogo(editing.$id, formData);
      if (success) {
        setEditing(null);
        setActiveTab('lista');
      }
      return success;
    } else {
      const success = await cadastrarCatalogo(formData);
      if (success) {
        setTimeout(() => setActiveTab('lista'), 2000);
      }
      return success;
    }
  };

  const handleEdit = (catalogoProduto: Models.Document) => {
    setEditing(catalogoProduto);
    setActiveTab('cadastro');
  };

  const handleCancelEdit = () => {
    setEditing(null);
    setActiveTab('lista');
  };

  const handlePrevPage = async () => {
    if (currentPage > 1) {
      if (searchTerm.trim()) {
        await buscarCatalogo(searchTerm, currentPage - 1);
      } else {
        await listarCatalogo(currentPage - 1);
      }
    }
  };

  const handleSearch = async (term: string) => {
    setSearchTerm(term);
    if (term.trim()) {
      await buscarCatalogo(term, 1);
    } else {
      await listarCatalogo(1);
    }
  };

  const handleNextPage = async () => {
    const totalPages = Math.ceil(totalCatalogoProdutos / 10);
    if (currentPage < totalPages) {
      if (searchTerm.trim()) {
        await buscarCatalogo(searchTerm, currentPage + 1);
      } else {
        await listarCatalogo(currentPage + 1);
      }
    }
  };

  if (!user) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
          <p className="text-gray-600">Verificando autenticação...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header 
        user={user} 
        title="Gestão de Catálogo de Produtos"
        subtitle="Gerencie os catálogos de produtos da plataforma SaveInMed"
      />
      
      <main className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        {/* Navegação por Tabs */}
        <div className="mb-6">
          <nav className="flex space-x-8 bg-white p-4 rounded-lg shadow-sm">
            <button
              onClick={() => {
                setActiveTab('lista');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'lista'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
              📋 Listar Catálogo de Produtos
            </button>
            <button
              onClick={() => {
                setActiveTab('cadastro');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'cadastro'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
               Cadastrar Catálogo de Produto
            </button>
          </nav>
        </div>

        {/* Conteúdo das Tabs */}
        {activeTab === 'lista' && (
          <CatalogoProdutosList
            catalogoProdutos={catalogoProdutos}
            loading={loading}
            error={error}
            totalCatalogoProdutos={totalCatalogoProdutos}
            currentPage={currentPage}
            pageSize={10}
            onEdit={handleEdit}
            onDelete={deletarCatalogo}
            onRefresh={() =>
              searchTerm.trim()
                ? buscarCatalogo(searchTerm, currentPage)
                : listarCatalogo(currentPage)
            }
            onPrevPage={handlePrevPage}
            onNextPage={handleNextPage}
            onSearch={handleSearch}
          />
        )}

        {activeTab === 'cadastro' && (
          <CatalogoProdutoForm
            onSubmit={handleFormSubmit}
            onCancel={editing ? handleCancelEdit : undefined}
            initialData={editing}
            loading={loading}
          />
        )}
      </main>
    </div>
  );
};

export default GestaoCatalogoProdutos;



src/app/categorias/page.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import CategoriaForm from '@/components/CategoriaForm';
import CategoriaList from '@/components/CategoriaList';
import { useCategorias, CategoriaFormData } from '@/hooks/useCategorias';

const GestaoCategorias = () => {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [editing, setEditing] = useState<Models.Document | null>(null);
  const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
  const [searchTerm, setSearchTerm] = useState('');
  
  const {
    categorias,
    loading,
    error,
    totalCategorias,
    currentPage,
    listarCategorias,
    buscarCategorias,
    cadastrarCategoria,
    atualizarCategoria,
    deletarCategoria,
    setCurrentPage
  } = useCategorias();

  // 🔐 Verificar autenticação
  useEffect(() => {
    const initializeUser = async () => {
      try {
        const currentUser = await account.get();
        setUser(currentUser);
        
        if (activeTab === 'lista') {
          await listarCategorias();
        }
      } catch (error) {
        console.error('❌ Usuário não autenticado:', error);
        router.push('/');
      }
    };

    initializeUser();
  }, [activeTab, router, listarCategorias]);

  const handleFormSubmit = async (formData: CategoriaFormData): Promise<boolean> => {
    if (editing) {
      const success = await atualizarCategoria(editing.$id, formData);
      if (success) {
        setEditing(null);
        setActiveTab('lista');
      }
      return success;
    } else {
      const success = await cadastrarCategoria(formData);
      if (success) {
        setTimeout(() => setActiveTab('lista'), 2000);
      }
      return success;
    }
  };

  const handleEdit = (lab: Models.Document) => {
    setEditing(lab);
    setActiveTab('cadastro');
  };

  const handleCancelEdit = () => {
    setEditing(null);
    setActiveTab('lista');
  };

  const handlePrevPage = async () => {
    if (currentPage > 1) {
      if (searchTerm.trim()) {
        await buscarCategorias(searchTerm, currentPage - 1);
      } else {
        await listarCategorias(currentPage - 1);
      }
    }
  };

  const handleSearch = async (term: string) => {
    setSearchTerm(term);
    if (term.trim()) {
      await buscarCategorias(term, 1);
    } else {
      await listarCategorias(1);
    }
  };

  const handleNextPage = async () => {
    const totalPages = Math.ceil(totalCategorias / 10);
    if (currentPage < totalPages) {
      if (searchTerm.trim()) {
        await buscarCategorias(searchTerm, currentPage + 1);
      } else {
        await listarCategorias(currentPage + 1);
      }
    }
  };

  if (!user) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
          <p className="text-gray-600">Verificando autenticação...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header 
        user={user} 
        title="Gestão de Categorias"
        subtitle="Gerencie as categorias da plataforma SaveInMed"
      />
      
      <main className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        {/* Navegação por Tabs */}
        <div className="mb-6">
          <nav className="flex space-x-8 bg-white p-4 rounded-lg shadow-sm">
            <button
              onClick={() => {
                setActiveTab('lista');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'lista'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
              📋 Listar Categorias
            </button>
            <button
              onClick={() => {
                setActiveTab('cadastro');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'cadastro'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
               Cadastrar Categoria
            </button>
          </nav>
        </div>

        {/* Conteúdo das Tabs */}
        {activeTab === 'lista' && (
          <CategoriaList
            categorias={categorias}
            loading={loading}
            error={error}
            totalCategorias={totalCategorias}
            currentPage={currentPage}
            pageSize={10}
            onEdit={handleEdit}
            onDelete={deletarCategoria}
            onRefresh={() =>
              searchTerm.trim()
                ? buscarCategorias(searchTerm, currentPage)
                : listarCategorias(currentPage)
            }
            onPrevPage={handlePrevPage}
            onNextPage={handleNextPage}
            onSearch={handleSearch}
          />
        )}

        {activeTab === 'cadastro' && (
          <CategoriaForm
            onSubmit={handleFormSubmit}
            onCancel={editing ? handleCancelEdit : undefined}
            initialData={editing}
            loading={loading}
          />
        )}
      </main>
    </div>
  );
};

export default GestaoCategorias;


src/app/dashboard/empresa-novo/page.tsx

'use client';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import EmpresaList from '@/components/EmpresaList';

const GestaoEmpresas = () => {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [loading, setLoading] = useState(false);
  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
  const [empresas, setEmpresas] = useState<any[]>([]);
  const [editingEmpresa, setEditingEmpresa] = useState<any>(null);
  const [activeTab, setActiveTab] = useState<'cadastro' | 'lista' | 'permissoes'>('lista');
  const [permissions, setPermissions] = useState<any>(null);
  
  const [formData, setFormData] = useState({
    cnpj: '',
    razaoSocial: '',
    nomeFantasia: ''
  });

  // 🔐 Verificar autenticação e carregar dados
  useEffect(() => {
    const initializeUser = async () => {
      try {
        const currentUser = await account.get();
        setUser(currentUser);
        
        if (activeTab === 'lista') {
          await listarEmpresas();
        } else if (activeTab === 'permissoes') {
          await verificarPermissoes();
        }
      } catch (error) {
        console.error('❌ Usuário não autenticado:', error);
        router.push('/');
      }
    };
    
    initializeUser();
  }, [activeTab, router]);

  // 🔐 Verificar permissões do usuário
  const verificarPermissoes = async () => {
    console.log('🔐 Verificando permissões do usuário...');
    setLoading(true);
    
    try {
      const response = await fetch('/api/user/permissions');
      const data = await response.json();
      
      if (data.success) {
        console.log('✅ Permissões carregadas:', data.permissions);
        setPermissions(data.permissions);
      } else {
        console.error('❌ Erro ao carregar permissões:', data.error);
        setMessage({ type: 'error', text: 'Erro ao verificar permissões.' });
      }
    } catch (error) {
      console.error('💥 Erro na verificação de permissões:', error);
      setMessage({ type: 'error', text: 'Erro de conexão ao verificar permissões.' });
    } finally {
      setLoading(false);
    }
  };

  // 📋 Listar empresas via API
  const listarEmpresas = async () => {
    console.log('📋 Listando empresas via API...');
    setLoading(true);
    
    try {
      const response = await fetch('/api/empresas');
      const data = await response.json();
      
      if (data.success) {
        console.log('✅ Empresas carregadas:', data.documents?.length || 0);
        setEmpresas(data.documents || []);
        setMessage({ 
          type: 'success', 
          text: `📊 ${data.documents?.length || 0} empresas carregadas!` 
        });
      } else {
        console.error('❌ Erro ao carregar empresas:', data.error);
        setMessage({ type: 'error', text: 'Erro ao carregar empresas.' });
      }
    } catch (error) {
      console.error('💥 Erro na listagem:', error);
      setMessage({ type: 'error', text: 'Erro de conexão ao carregar empresas.' });
    } finally {
      setLoading(false);
    }
  };

  //  Cadastrar empresa via API
  const cadastrarEmpresa = async (e: React.FormEvent) => {
    e.preventDefault();
    console.log(' Cadastrando empresa via API...');
    
    if (!validarCNPJ(formData.cnpj)) {
      setMessage({ type: 'error', text: 'CNPJ inválido.' });
      return;
    }
    
    setLoading(true);
    
    try {
      const payload = {
        documentId: 'unique()',
        data: {
          cnpj: formData.cnpj.replace(/\D/g, ''),
          'razao-social': formData.razaoSocial,
          'nome-fantasia': formData.nomeFantasia
        }
      };
      
      console.log('📤 Enviando dados:', payload);
      
      const response = await fetch('/api/empresas', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload)
      });
      
      const data = await response.json();
      
      if (data.success) {
        console.log('✅ Empresa cadastrada com sucesso!');
        setMessage({ type: 'success', text: '🎉 Empresa cadastrada com sucesso!' });
        setFormData({ cnpj: '', razaoSocial: '', nomeFantasia: '' });
        
        // 🔄 Redirecionar para lista após 2 segundos
        setTimeout(() => {
          setActiveTab('lista');
        }, 2000);
      } else {
        console.error('❌ Erro no cadastro:', data.error);
        setMessage({ type: 'error', text: 'Erro ao cadastrar empresa.' });
      }
    } catch (error) {
      console.error('💥 Erro no cadastro:', error);
      setMessage({ type: 'error', text: 'Erro de conexão ao cadastrar empresa.' });
    } finally {
      setLoading(false);
    }
  };

  // 🔄 Atualizar empresa via API
  const atualizarEmpresa = async (empresaId: string, dadosAtualizados: any) => {
    console.log('🔄 Atualizando empresa via API:', empresaId);
    setLoading(true);
    
    try {
      const payload = {
        data: {
          cnpj: dadosAtualizados.cnpj.replace(/\D/g, ''),
          'razao-social': dadosAtualizados.razaoSocial,
          'nome-fantasia': dadosAtualizados.nomeFantasia
        }
      };
      
      console.log('📤 Dados para atualização:', payload);
      
      const response = await fetch(`/api/empresas/${empresaId}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload)
      });
      
      const data = await response.json();
      
      if (data.success) {
        console.log('✅ Empresa atualizada com sucesso!');
        setMessage({ type: 'success', text: '🔄 Empresa atualizada com sucesso!' });
        setEditingEmpresa(null);
        await listarEmpresas();
      } else {
        console.error('❌ Erro na atualização:', data.error);
        setMessage({ type: 'error', text: 'Erro ao atualizar empresa.' });
      }
    } catch (error) {
      console.error('💥 Erro na atualização:', error);
      setMessage({ type: 'error', text: 'Erro de conexão ao atualizar empresa.' });
    } finally {
      setLoading(false);
    }
  };

  // 🗑️ Deletar empresa via API
  const deletarEmpresa = async (empresaId: string): Promise<boolean> => {
    console.log('🗑️ Deletando empresa via API:', empresaId);

    if (!confirm('🗑️ Tem certeza que deseja deletar esta empresa?')) {
      return false;
    }

    setLoading(true);

    try {
      const response = await fetch(`/api/empresas/${empresaId}`, {
        method: 'DELETE'
      });

      const data = await response.json();

      if (data.success) {
        console.log('✅ Empresa deletada com sucesso!');
        setMessage({ type: 'success', text: '🗑️ Empresa deletada com sucesso!' });
        await listarEmpresas();
        return true;
      } else {
        console.error('❌ Erro na exclusão:', data.error);
        setMessage({ type: 'error', text: 'Erro ao deletar empresa.' });
        return false;
      }
    } catch (error) {
      console.error('💥 Erro na exclusão:', error);
      setMessage({ type: 'error', text: 'Erro de conexão ao deletar empresa.' });
      return false;
    } finally {
      setLoading(false);
    }
  };

  // 🔧 Funções auxiliares
  const validarCNPJ = (cnpj: string): boolean => {
    const cnpjLimpo = cnpj.replace(/\D/g, '');
    if (cnpjLimpo.length !== 14) return false;
    
    // Validação básica dos dígitos verificadores
    let soma = 0;
    let peso = 2;
    
    for (let i = 11; i >= 0; i--) {
      soma += parseInt(cnpjLimpo[i]) * peso;
      peso = peso === 9 ? 2 : peso + 1;
    }
    
    const resto = soma % 11;
    const digito1 = resto < 2 ? 0 : 11 - resto;
    
    if (parseInt(cnpjLimpo[12]) !== digito1) return false;
    
    soma = 0;
    peso = 2;
    
    for (let i = 12; i >= 0; i--) {
      soma += parseInt(cnpjLimpo[i]) * peso;
      peso = peso === 9 ? 2 : peso + 1;
    }
    
    const resto2 = soma % 11;
    const digito2 = resto2 < 2 ? 0 : 11 - resto2;
    
    return parseInt(cnpjLimpo[13]) === digito2;
  };

  const formatarCNPJ = (valor: string): string => {
    const cnpjLimpo = valor.replace(/\D/g, '');
    return cnpjLimpo
      .replace(/(\d{2})(\d)/, '$1.$2')
      .replace(/(\d{3})(\d)/, '$1.$2')
      .replace(/(\d{3})(\d)/, '$1/$2')
      .replace(/(\d{4})(\d)/, '$1-$2')
      .replace(/(-\d{2})\d+?$/, '$1');
  };

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    
    if (name === 'cnpj') {
      setFormData(prev => ({ ...prev, [name]: formatarCNPJ(value) }));
    } else {
      setFormData(prev => ({ ...prev, [name]: value }));
    }
    
    if (message) setMessage(null);
  };

  const iniciarEdicao = (empresa: any) => {
    setEditingEmpresa(empresa);
    setFormData({
      cnpj: formatarCNPJ(empresa.cnpj || ''),
      razaoSocial: empresa['razao-social'] || '',
      nomeFantasia: empresa['nome-fantasia'] || ''
    });
    // 🔧 FIX: Mudar para aba de cadastro ao editar
    setActiveTab('cadastro');
  };

  const cancelarEdicao = () => {
    setEditingEmpresa(null);
    setFormData({ cnpj: '', razaoSocial: '', nomeFantasia: '' });
  };

  const salvarEdicao = async (e: React.FormEvent) => {
    e.preventDefault();
    if (editingEmpresa) {
      await atualizarEmpresa(editingEmpresa.$id, formData);
    }
  };

  // 🔄 Logout
  const logout = async () => {
    try {
      await account.deleteSession('current');
      router.push('/');
    } catch (error) {
      console.error('Erro no logout:', error);
    }
  };

  return (
    <div className="min-h-screen bg-gradient-to-br from-blue-50 to-green-50">
      <Header 
        user={user} 
        title="Gestão de Empresas" 
        subtitle="SaveInMed - Plataforma B2B" 
        showBackButton={true} 
      />

      {/* 📋 Navegação por abas */}
      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
        <div className="flex space-x-4">
          <button
            onClick={() => setActiveTab('lista')}
            className={`px-4 py-2 rounded-lg font-medium transition-colors cursor-pointer ${
              activeTab === 'lista'
                ? 'bg-blue-600 text-white'
                : 'bg-white text-gray-600 hover:bg-gray-50'
            }`}
          >
            📋 Listar Empresas
          </button>
          <button
            onClick={() => setActiveTab('cadastro')}
            className={`px-4 py-2 rounded-lg font-medium transition-colors cursor-pointer ${
              activeTab === 'cadastro'
                ? 'bg-blue-600 text-white'
                : 'bg-white text-gray-600 hover:bg-gray-50'
            }`}
          >
             Cadastrar Empresa
          </button>
          <button
            onClick={() => setActiveTab('permissoes')}
            className={`px-4 py-2 rounded-lg font-medium transition-colors cursor-pointer ${
              activeTab === 'permissoes'
                ? 'bg-blue-600 text-white'
                : 'bg-white text-gray-600 hover:bg-gray-50'
            }`}
          >
            🔐 Permissões
          </button>
        </div>
      </div>

      {/* 📄 Conteúdo principal */}
      <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-8">
        {/* 💬 Mensagem de feedback */}
        {message && (
          <div className={`mb-6 p-4 rounded-lg ${
            message.type === 'success' 
              ? 'bg-green-50 border border-green-200 text-green-800' 
              : 'bg-red-50 border border-red-200 text-red-800'
          }`}>
            <div className="flex items-center">
              {message.type === 'success' ? (
                <svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
                  <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
                </svg>
              ) : (
                <svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
                  <path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
                </svg>
              )}
              {message.text}
            </div>
          </div>
        )}

        {/* 📋 Aba de Lista */}
        {activeTab === 'lista' && (
          <EmpresaList
            empresas={empresas}
            loading={loading}
            error={null}
            onEdit={iniciarEdicao}
            onDelete={deletarEmpresa}
            onRefresh={listarEmpresas}
          />
        )}

        {/*  Aba de Cadastro */}
        {activeTab === 'cadastro' && (
          <div className="bg-white rounded-lg shadow-sm border">
            <div className="p-6">
              <h2 className="text-xl font-semibold text-gray-900 mb-6">
                {editingEmpresa ? '✏️ Editar Empresa' : ' Nova Empresa'}
              </h2>
              <p className="text-gray-600 mb-6">
                {editingEmpresa ? 'Atualize os dados da empresa.' : 'Cadastre uma nova empresa na plataforma SaveInMed.'}
              </p>
              
              <form onSubmit={editingEmpresa ? salvarEdicao : cadastrarEmpresa} className="space-y-6">
                <div>
                  <label htmlFor="cnpj" className="block text-sm font-medium text-gray-700 mb-2">
                    🆔 CNPJ *
                  </label>
                  <input
                    type="text"
                    id="cnpj"
                    name="cnpj"
                    value={formData.cnpj}
                    onChange={handleInputChange}
                    placeholder="00.000.000/0001-00"
                    maxLength={18}
                    required
                    className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors bg-white text-gray-900 placeholder-gray-500"
                  />
                </div>
                
                <div>
                  <label htmlFor="razaoSocial" className="block text-sm font-medium text-gray-700 mb-2">
                    📄 Razão Social *
                  </label>
                  <input
                    type="text"
                    id="razaoSocial"
                    name="razaoSocial"
                    value={formData.razaoSocial}
                    onChange={handleInputChange}
                    placeholder="Razão Social da Empresa"
                    required
                    className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors bg-white text-gray-900 placeholder-gray-500"
                  />
                </div>
                
                <div>
                  <label htmlFor="nomeFantasia" className="block text-sm font-medium text-gray-700 mb-2">
                    🏢 Nome Fantasia *
                  </label>
                  <input
                    type="text"
                    id="nomeFantasia"
                    name="nomeFantasia"
                    value={formData.nomeFantasia}
                    onChange={handleInputChange}
                    placeholder="Nome Fantasia da Empresa"
                    required
                    className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors bg-white text-gray-900 placeholder-gray-500"
                  />
                </div>
                
                <div className="flex space-x-4">
                  <button
                    type="submit"
                    disabled={loading}
                    className="flex-1 bg-gradient-to-r from-blue-600 to-green-600 text-white py-3 px-6 rounded-lg font-medium hover:from-blue-700 hover:to-green-700 disabled:opacity-50 transition-all duration-200 flex items-center justify-center cursor-pointer"
                  >
                    {loading ? (
                      <>
                        <div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin mr-2"></div>
                        Processando...
                      </>
                    ) : (
                      <>
                        {editingEmpresa ? '🔄 Atualizar' : '✅ Salvar'}
                      </>
                    )}
                  </button>
                  
                  {editingEmpresa && (
                    <button
                      type="button"
                      onClick={cancelarEdicao}
                      className="px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors cursor-pointer"
                    >
                       Cancelar
                    </button>
                  )}
                </div>
              </form>
            </div>
          </div>
        )}

        {/* 🔐 Aba de Permissões */}
        {activeTab === 'permissoes' && (
          <div className="bg-white rounded-lg shadow-sm border">
            <div className="p-6">
              <div className="flex justify-between items-center mb-6">
                <h2 className="text-xl font-semibold text-gray-900">🔐 Permissões do Usuário</h2>
                <button
                  onClick={verificarPermissoes}
                  disabled={loading}
                  className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 transition-colors cursor-pointer"
                >
                  {loading ? '🔄 Verificando...' : '🔄 Atualizar'}
                </button>
              </div>
              
              {loading ? (
                <div className="text-center py-8">
                  <div className="w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
                  <p className="text-gray-600">Verificando permissões...</p>
                </div>
              ) : permissions ? (
                <div className="space-y-4">
                  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                    <div className="p-4 bg-gray-50 rounded-lg">
                      <h3 className="font-semibold text-gray-900 mb-2">🔑 Status da API Key</h3>
                      <p className={`text-sm ${
                        permissions.apiKeyValid ? 'text-green-600' : 'text-red-600'
                      }`}>
                        {permissions.apiKeyValid ? '✅ Válida' : '❌ Inválida'}
                      </p>
                    </div>
                    
                    <div className="p-4 bg-gray-50 rounded-lg">
                      <h3 className="font-semibold text-gray-900 mb-2">📊 Status HTTP</h3>
                      <p className={`text-sm ${
                        permissions.status === 200 ? 'text-green-600' : 'text-red-600'
                      }`}>
                        {permissions.status}
                      </p>
                    </div>
                    
                    <div className="p-4 bg-gray-50 rounded-lg">
                      <h3 className="font-semibold text-gray-900 mb-2">📖 Permissão de Leitura</h3>
                      <p className={`text-sm ${
                        permissions.canRead ? 'text-green-600' : 'text-red-600'
                      }`}>
                        {permissions.canRead ? '✅ Permitida' : '❌ Negada'}
                      </p>
                    </div>
                    
                    <div className="p-4 bg-gray-50 rounded-lg">
                      <h3 className="font-semibold text-gray-900 mb-2">✏️ Permissão de Escrita</h3>
                      <p className={`text-sm ${
                        permissions.canWrite ? 'text-green-600' : 'text-red-600'
                      }`}>
                        {permissions.canWrite ? '✅ Permitida' : '❌ Negada'}
                      </p>
                    </div>
                    
                    <div className="p-4 bg-gray-50 rounded-lg">
                      <h3 className="font-semibold text-gray-900 mb-2">🔄 Permissão de Atualização</h3>
                      <p className={`text-sm ${
                        permissions.canUpdate ? 'text-green-600' : 'text-red-600'
                      }`}>
                        {permissions.canUpdate ? '✅ Permitida' : '❌ Negada'}
                      </p>
                    </div>
                    
                    <div className="p-4 bg-gray-50 rounded-lg">
                      <h3 className="font-semibold text-gray-900 mb-2">🗑️ Permissão de Exclusão</h3>
                      <p className={`text-sm ${
                        permissions.canDelete ? 'text-green-600' : 'text-red-600'
                      }`}>
                        {permissions.canDelete ? '✅ Permitida' : '❌ Negada'}
                      </p>
                    </div>
                  </div>
                  
                  <div className="mt-6 p-4 bg-blue-50 rounded-lg">
                    <h3 className="font-semibold text-gray-900 mb-2">📋 Informações Técnicas</h3>
                    <div className="text-sm text-gray-600 space-y-1">
                      <p><strong>🔑 Tipo:</strong> {permissions.apiKeyType}</p>
                      <p><strong>📁 Projeto:</strong> {permissions.project}</p>
                      <p><strong>🗄️ Database:</strong> {permissions.database}</p>
                      <p><strong>📊 Collection:</strong> {permissions.collection}</p>
                      <p><strong> Verificado em:</strong> {new Date(permissions.timestamp).toLocaleString('pt-BR')}</p>
                    </div>
                  </div>
                </div>
              ) : (
                <div className="text-center py-8">
                  <p className="text-gray-500">🔐 Clique em "Atualizar" para verificar as permissões.</p>
                </div>
              )}
            </div>
          </div>
        )}
      </main>
    </div>
  );
};

export default GestaoEmpresas;

src/app/dashboard/page.tsx

'use client';

import { useState, useEffect } from 'react';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import { useRouter } from 'next/navigation';
import Header from '@/components/Header';

/**
 * Dashboard principal da plataforma SaveInMed
 * Plataforma B2B para farmácias comprarem e venderem medicamentos próximos ao vencimento
 * Funcionalidades: gestão de estoque, pedidos F2F, catálogo com validade destacada
 */
const Dashboard = () => {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [loading, setLoading] = useState<boolean>(true);
  
  // Estatísticas da farmácia na plataforma B2B
  const [stats] = useState({
    medicamentosDisponiveis: 156, // Medicamentos disponíveis para venda
    pedidosRecebidos: 12, // Pedidos de outras farmácias
    vendasMes: 8, // Vendas realizadas este mês
    economiaGerada: 15420 // Economia gerada em R$ com a plataforma
  });

  /**
   * Verifica autenticação do usuário ao carregar o dashboard
   * Redireciona para login se não estiver autenticado
   */
  useEffect(() => {
    const getUser = async () => {
      try {
        const currentUser = await account.get();
        setUser(currentUser);
      } catch (error) {
        console.error('Usuário não autenticado:', error);
        router.push('/');
      } finally {
        setLoading(false);
      }
    };
    getUser();
  }, [router]);

  // Tela de carregamento
  if (loading) {
    return (
      <div className="min-h-screen bg-gradient-to-br from-blue-50 to-green-50 flex items-center justify-center">
        <div className="text-center">
          <div className="w-16 h-16 border-4 border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
          <p className="text-gray-600">Carregando dashboard...</p>
        </div>
      </div>
    );
  }

  if (!user) {
    return null;
  }

  return (
    <div className="min-h-screen bg-gradient-to-br from-blue-50 to-green-50">
      {/* Header unificado */}
      <Header user={user} />

      {/* Conteúdo principal com espaçamento adequado */}
      <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
        {/* Seção de boas-vindas */}
        <div className="mb-8">
          <h2 className="text-3xl font-bold text-gray-900 mb-2">
            Bem-vindo, {user.name}
          </h2>
          <p className="text-gray-600">
            Gerencie seus medicamentos próximos ao vencimento e conecte-se com outras farmácias.
          </p>
        </div>

        {/* Cards de estatísticas B2B */}
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
          {/* Medicamentos Disponíveis */}
          <div className="bg-white rounded-xl shadow-sm p-6 border border-gray-100">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-sm font-medium text-gray-600">Medicamentos Disponíveis</p>
                <p className="text-3xl font-bold text-gray-900">{stats.medicamentosDisponiveis}</p>
                <p className="text-xs text-blue-600 mt-1">
                  <span className="font-medium">23</span> próximos ao vencimento
                </p>
              </div>
              <div className="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center">
                <svg className="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
                </svg>
              </div>
            </div>
          </div>
          
          {/* Pedidos Recebidos */}
          <div className="bg-white rounded-xl shadow-sm p-6 border border-gray-100">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-sm font-medium text-gray-600">Pedidos Recebidos</p>
                <p className="text-3xl font-bold text-gray-900">{stats.pedidosRecebidos}</p>
                <p className="text-xs text-green-600 mt-1">
                  <span className="font-medium">5</span> pendentes
                </p>
              </div>
              <div className="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center">
                <svg className="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" />
                </svg>
              </div>
            </div>
          </div>
          
          {/* Vendas do Mês */}
          <div className="bg-white rounded-xl shadow-sm p-6 border border-gray-100">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-sm font-medium text-gray-600">Vendas do Mês</p>
                <p className="text-3xl font-bold text-gray-900">{stats.vendasMes}</p>
                <p className="text-xs text-orange-600 mt-1">
                  <span className="font-medium">+25%</span> vs mês anterior
                </p>
              </div>
              <div className="w-12 h-12 bg-orange-100 rounded-lg flex items-center justify-center">
                <svg className="w-6 h-6 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
                </svg>
              </div>
            </div>
          </div>
          
          {/* Economia Gerada */}
          <div className="bg-white rounded-xl shadow-sm p-6 border border-gray-100">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-sm font-medium text-gray-600">Economia Gerada</p>
                <p className="text-3xl font-bold text-green-600">R$ {stats.economiaGerada.toLocaleString()}</p>
                <p className="text-xs text-green-600 mt-1">
                  Recuperação de investimento
                </p>
              </div>
              <div className="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center">
                <svg className="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1" />
                </svg>
              </div>
            </div>
          </div>
        </div>

        {/* Resto do conteúdo permanece igual... */}
        {/* Grid de conteúdo */}
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
          {/* Atividade Recente F2F */}
          <div className="bg-white rounded-xl shadow-sm p-6 border border-gray-100">
            <h3 className="text-lg font-semibold text-gray-900 mb-4">Atividade Recente F2F</h3>
            <div className="space-y-4">
              <div className="flex items-center space-x-3">
                <div className="w-2 h-2 bg-blue-500 rounded-full"></div>
                <div className="flex-1">
                  <p className="text-sm font-medium text-gray-900">Farmácia Central comprou Dipirona 500mg</p>
                  <p className="text-xs text-gray-500">Lote vencendo em 45 dias -  2 horas</p>
                </div>
              </div>
              <div className="flex items-center space-x-3">
                <div className="w-2 h-2 bg-green-500 rounded-full"></div>
                <div className="flex-1">
                  <p className="text-sm font-medium text-gray-900">Você vendeu Amoxicilina 875mg para Farmácia Saúde</p>
                  <p className="text-xs text-gray-500">Desconto de 30% aplicado -  4 horas</p>
                </div>
              </div>
              <div className="flex items-center space-x-3">
                <div className="w-2 h-2 bg-orange-500 rounded-full"></div>
                <div className="flex-1">
                  <p className="text-sm font-medium text-gray-900">Novo lote de Paracetamol cadastrado</p>
                  <p className="text-xs text-gray-500">Vencimento em 60 dias -  6 horas</p>
                </div>
              </div>
            </div>
          </div>
          
          {/* Pedidos Pendentes */}
          <div className="bg-white rounded-xl shadow-sm p-6 border border-gray-100">
            <h3 className="text-lg font-semibold text-gray-900 mb-4">Pedidos Pendentes</h3>
            <div className="space-y-4">
              <div className="flex items-center justify-between p-3 bg-blue-50 rounded-lg">
                <div>
                  <p className="text-sm font-medium text-gray-900">Farmácia Bem Estar</p>
                  <p className="text-xs text-gray-500">Ibuprofeno 600mg - 50 unidades</p>
                </div>
                <span className="text-sm font-medium text-blue-600">R$ 245,00</span>
              </div>
              <div className="flex items-center justify-between p-3 bg-green-50 rounded-lg">
                <div>
                  <p className="text-sm font-medium text-gray-900">Drogaria Popular</p>
                  <p className="text-xs text-gray-500">Losartana 50mg - 30 unidades</p>
                </div>
                <span className="text-sm font-medium text-green-600">R$ 89,90</span>
              </div>
              <div className="flex items-center justify-between p-3 bg-orange-50 rounded-lg">
                <div>
                  <p className="text-sm font-medium text-gray-900">Farmácia do Bairro</p>
                  <p className="text-xs text-gray-500">Omeprazol 20mg - 28 unidades</p>
                </div>
                <span className="text-sm font-medium text-orange-600">R$ 156,80</span>
              </div>
            </div>
          </div>
        </div>

        {/* 🚀 Seção de Ações Rápidas - com espaçamento e alinhamento otimizados */}
        <div className="bg-white rounded-lg shadow-sm border py-4 px-5">
          <div className="flex items-center gap-3 py-4 px-5 min-h-[48px]">
            <div className="w-6 h-6 flex items-center justify-center">
              <span className="text-xl">🚀</span>
            </div>
            <h2 className="text-xl font-semibold text-gray-900">Ações Rápidas</h2>
          </div>
          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 px-5 pb-4">
            {/* 🏢 Gestão de Empresas - seguindo padrão */}
            <button
              onClick={() => router.push('/dashboard/empresa-novo')}
              className="bg-white hover:bg-gray-50 border border-gray-200 rounded-xl p-6 text-center transition-colors duration-200 cursor-pointer group min-h-[48px]"
            >
              <div className="w-12 h-12 bg-blue-100 rounded-lg mx-auto mb-4 flex items-center justify-center group-hover:bg-blue-200 transition-colors">
                <svg className="w-6 h-6 text-blue-600" fill="currentColor" viewBox="0 0 20 20">
                  <path d="M4 4a2 2 0 00-2 2v8a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2H4zm0 2h12v8H4V6z" />
                </svg>
              </div>
              <div className="flex items-center justify-center gap-3 min-h-[48px]">
                <div className="w-6 h-6 flex items-center justify-center">
                  <span className="text-lg">🏢</span>
                </div>
                <div className="text-left">
                  <h3 className="font-medium text-gray-900 mb-2">Gestão de Empresas</h3>
                  <p className="text-sm text-gray-500">Listar e gerenciar empresas</p>
                </div>
              </div>
            </button>
            
            {/* Cadastrar Medicamento */}
            <button className="bg-white hover:bg-gray-50 border border-gray-200 rounded-xl p-6 text-center transition-colors duration-200 cursor-pointer group min-h-[48px]">
              <div className="w-12 h-12 bg-blue-100 rounded-lg mx-auto mb-4 flex items-center justify-center group-hover:bg-blue-200 transition-colors">
                <svg className="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
                </svg>
              </div>
              <h3 className="font-medium text-gray-900 mb-2">Cadastrar Medicamento</h3>
              <p className="text-sm text-gray-500">Adicionar novos medicamentos</p>
            </button>
            
            {/* Buscar Medicamentos */}
            <button className="bg-white hover:bg-gray-50 border border-gray-200 rounded-xl p-6 text-center transition-colors duration-200 cursor-pointer group min-h-[48px]">
              <div className="w-12 h-12 bg-green-100 rounded-lg mx-auto mb-4 flex items-center justify-center group-hover:bg-green-200 transition-colors">
                <svg className="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
                </svg>
              </div>
              <h3 className="font-medium text-gray-900 mb-2">Buscar Medicamentos</h3>
              <p className="text-sm text-gray-500">Encontrar medicamentos disponíveis</p>
            </button>
            
            {/* Gestão de Pedidos */}
            <button className="bg-white hover:bg-gray-50 border border-gray-200 rounded-xl p-6 text-center transition-colors duration-200 cursor-pointer group min-h-[48px]">
              <div className="w-12 h-12 bg-orange-100 rounded-lg mx-auto mb-4 flex items-center justify-center group-hover:bg-orange-200 transition-colors">
                <svg className="w-6 h-6 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
                </svg>
              </div>
              <h3 className="font-medium text-gray-900 mb-2">Gestão de Pedidos</h3>
              <p className="text-sm text-gray-500">Gerenciar pedidos e vendas</p>
            </button>
            
            {/* Relatórios */}
            <button className="bg-white hover:bg-gray-50 border border-gray-200 rounded-xl p-6 text-center transition-colors duration-200 cursor-pointer group min-h-[48px]">
              <div className="w-12 h-12 bg-purple-100 rounded-lg mx-auto mb-4 flex items-center justify-center group-hover:bg-purple-200 transition-colors">
                <svg className="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
                </svg>
              </div>
              <h3 className="font-medium text-gray-900 mb-2">Relatórios</h3>
              <p className="text-sm text-gray-500">Visualizar relatórios e métricas</p>
            </button>
          </div>
        </div>
      </main>
    </div>
  );
};

export default Dashboard;

src/app/enderecos/page.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import EnderecoForm from '@/components/EnderecoForm';
import EnderecoList from '@/components/EnderecoList';
import { useEnderecos, EnderecoData } from '@/hooks/useEnderecos';

const GestaoEnderecos = () => {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [editing, setEditing] = useState<Models.Document | null>(null);
  const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
  const [searchTerm, setSearchTerm] = useState('');

  const {
    enderecos,
    loading,
    error,
    totalEnderecos,
    currentPage,
    listarEnderecos,
    buscarEnderecos,
    cadastrarEndereco,
    atualizarEndereco,
    deletarEndereco,
    setCurrentPage
  } = useEnderecos();

  useEffect(() => {
    const initializeUser = async () => {
      try {
        const currentUser = await account.get();
        setUser(currentUser);

        if (activeTab === 'lista') {
          await listarEnderecos();
        }
      } catch (error) {
        console.error('❌ Usuário não autenticado:', error);
        router.push('/');
      }
    };

    initializeUser();
  }, [activeTab, router, listarEnderecos]);

  const handleFormSubmit = async (formData: EnderecoData): Promise<boolean> => {
    if (editing) {
      const success = await atualizarEndereco(editing.$id, formData);
      if (success) {
        setEditing(null);
        setActiveTab('lista');
      }
      return success;
    } else {
      const success = await cadastrarEndereco(formData);
      if (success) {
        setTimeout(() => setActiveTab('lista'), 2000);
      }
      return success;
    }
  };

  const handleEdit = (endereco: Models.Document) => {
    setEditing(endereco);
    setActiveTab('cadastro');
  };

  const handleCancelEdit = () => {
    setEditing(null);
    setActiveTab('lista');
  };

  const handlePrevPage = async () => {
    if (currentPage > 1) {
      if (searchTerm.trim()) {
        await buscarEnderecos(searchTerm, currentPage - 1);
      } else {
        await listarEnderecos(currentPage - 1);
      }
    }
  };

  const handleSearch = async (term: string) => {
    setSearchTerm(term);
    if (term.trim()) {
      await buscarEnderecos(term, 1);
    } else {
      await listarEnderecos(1);
    }
  };

  const handleNextPage = async () => {
    const totalPages = Math.ceil(totalEnderecos / 10);
    if (currentPage < totalPages) {
      if (searchTerm.trim()) {
        await buscarEnderecos(searchTerm, currentPage + 1);
      } else {
        await listarEnderecos(currentPage + 1);
      }
    }
  };

  if (!user) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
          <p className="text-gray-600">Verificando autenticação...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header
        user={user}
        title="Gestão de Endereços"
        subtitle="Gerencie os endereços da plataforma SaveInMed"
      />

      <main className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        <div className="mb-6">
          <nav className="flex space-x-8 bg-white p-4 rounded-lg shadow-sm">
            <button
              onClick={() => {
                setActiveTab('lista');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'lista'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
              📋 Listar Endereços
            </button>
            <button
              onClick={() => {
                setActiveTab('cadastro');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'cadastro'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
               Cadastrar Endereço
            </button>
          </nav>
        </div>

        {activeTab === 'lista' && (
          <EnderecoList
            enderecos={enderecos}
            loading={loading}
            error={error}
            totalEnderecos={totalEnderecos}
            currentPage={currentPage}
            pageSize={10}
            onEdit={handleEdit}
            onDelete={deletarEndereco}
            onRefresh={() =>
              searchTerm.trim()
                ? buscarEnderecos(searchTerm, currentPage)
                : listarEnderecos(currentPage)
            }
            onPrevPage={handlePrevPage}
            onNextPage={handleNextPage}
            onSearch={handleSearch}
          />
        )}

        {activeTab === 'cadastro' && (
          <EnderecoForm
            onSubmit={handleFormSubmit}
            onCancel={editing ? handleCancelEdit : undefined}
            initialData={editing}
            loading={loading}
          />
        )}
      </main>
    </div>
  );
};

export default GestaoEnderecos;


src/app/faturas/page.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import FaturaForm from '@/components/FaturaForm';
import FaturaList from '@/components/FaturaList';
import { useFaturas, FaturaFormData } from '@/hooks/useFaturas';

const GestaoFaturas = () => {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [editing, setEditing] = useState<Models.Document | null>(null);
  const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
  const [searchTerm, setSearchTerm] = useState('');
  
  const {
    faturas,
    loading,
    error,
    totalFaturas,
    currentPage,
    listarFaturas,
    buscarFaturas,
    cadastrarFatura,
    atualizarFatura,
    deletarFatura,
    setCurrentPage
  } = useFaturas();

  // 🔐 Verificar autenticação
  useEffect(() => {
    const initializeUser = async () => {
      try {
        const currentUser = await account.get();
        setUser(currentUser);
        
        if (activeTab === 'lista') {
          await listarFaturas();
        }
      } catch (error) {
        console.error('❌ Usuário não autenticado:', error);
        router.push('/');
      }
    };

    initializeUser();
  }, [activeTab, router, listarFaturas]);

  const handleFormSubmit = async (formData: FaturaFormData): Promise<boolean> => {
    if (editing) {
      const success = await atualizarFatura(editing.$id, formData);
      if (success) {
        setEditing(null);
        setActiveTab('lista');
      }
      return success;
    } else {
      const success = await cadastrarFatura(formData);
      if (success) {
        setTimeout(() => setActiveTab('lista'), 2000);
      }
      return success;
    }
  };

  const handleEdit = (fatura: Models.Document) => {
    setEditing(fatura);
    setActiveTab('cadastro');
  };

  const handleCancelEdit = () => {
    setEditing(null);
    setActiveTab('lista');
  };

  const handlePrevPage = async () => {
    if (currentPage > 1) {
      if (searchTerm.trim()) {
        await buscarFaturas(searchTerm, currentPage - 1);
      } else {
        await listarFaturas(currentPage - 1);
      }
    }
  };

  const handleSearch = async (term: string) => {
    setSearchTerm(term);
    if (term.trim()) {
      await buscarFaturas(term, 1);
    } else {
      await listarFaturas(1);
    }
  };

  const handleNextPage = async () => {
    const totalPages = Math.ceil(totalFaturas / 10);
    if (currentPage < totalPages) {
      if (searchTerm.trim()) {
        await buscarFaturas(searchTerm, currentPage + 1);
      } else {
        await listarFaturas(currentPage + 1);
      }
    }
  };

  if (!user) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
          <p className="text-gray-600">Verificando autenticação...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header 
        user={user} 
        title="Gestão de Faturas"
        subtitle="Gerencie as faturas da plataforma SaveInMed"
      />
      
      <main className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        {/* Navegação por Tabs */}
        <div className="mb-6">
          <nav className="flex space-x-8 bg-white p-4 rounded-lg shadow-sm">
            <button
              onClick={() => {
                setActiveTab('lista');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'lista'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
              📋 Listar Faturas
            </button>
            <button
              onClick={() => {
                setActiveTab('cadastro');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'cadastro'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
               Cadastrar Fatura
            </button>
          </nav>
        </div>

        {/* Conteúdo das Tabs */}
        {activeTab === 'lista' && (
          <FaturaList
            faturas={faturas}
            loading={loading}
            error={error}
            totalFaturas={totalFaturas}
            currentPage={currentPage}
            pageSize={10}
            onEdit={handleEdit}
            onDelete={deletarFatura}
            onRefresh={() =>
              searchTerm.trim()
                ? buscarFaturas(searchTerm, currentPage)
                : listarFaturas(currentPage)
            }
            onPrevPage={handlePrevPage}
            onNextPage={handleNextPage}
            onSearch={handleSearch}
          />
        )}

        {activeTab === 'cadastro' && (
          <FaturaForm
            onSubmit={handleFormSubmit}
            onCancel={editing ? handleCancelEdit : undefined}
            initialData={editing}
            loading={loading}
          />
        )}
      </main>
    </div>
  );
};

export default GestaoFaturas;


src/app/favicon.ico

 (F   (n00 (-<2D> <20><1E>F(  $]<5D><>]$ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 8<><38><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>8<1F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>#<23><><EFBFBD>OOO<4F><4F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ggg<67><67><EFBFBD><EFBFBD>#Y<><59><EFBFBD><1F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>555<35><35><EFBFBD><EFBFBD>Y<EFBFBD><59><EFBFBD><EFBFBD><EFBFBD>kkk<6B><6B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>			<09><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Y<EFBFBD><59><EFBFBD><EFBFBD><EFBFBD>JJJ<4A><4A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>kkk<6B><6B><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Y#<23><><EFBFBD><EFBFBD><EFBFBD><01><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>			<09><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>111<31>DDD<44><44><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>8<><38><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>8 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> $]<5D><>]$( @ ,U<><55><EFBFBD><EFBFBD>U,*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*<1C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Q<><51><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Qr<51><72><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>rr<72><72><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>rO<72><4F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>O<1B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>888<38><38><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>___<5F><5F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>SSS<53><53><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+<2B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>hhh<68><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+T<><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>T<EFBFBD><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>GGG<47><47><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+++<2B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>jjj<6A><6A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>T<EFBFBD><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><16><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>III<49><49><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>T+<2B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>hhh<68><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><01><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+<07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>GGG<47><47><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>333<33>___<5F><5F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>O<><4F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Or<4F><72><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>rr<72><72><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>rQ<72><51><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Q<1C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*,U<><55><EFBFBD><EFBFBD>U,(0` -	(Lj<4C><6A><EFBFBD><EFBFBD>jK(	V<><56><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>U%<25><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>&<16><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Q<><51><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<06><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><06><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><06><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><50><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>O<15><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><15><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><11><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>$$$<24>hhh<68>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>eee<65>PPP<50><01><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>U<><55><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>sss<73><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>U<EFBFBD><55><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>eee<65><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>	<09><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>HHH<48><48><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>	(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>EEE<45><45><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(K<><4B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Lj<4C><6A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)))<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>j<EFBFBD><6A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><16><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><14><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>iii<69><69><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>eee<65><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>HHH<48><48><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>j<EFBFBD><6A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>EEE<45><45><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>jL<6A><4C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>K(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)))<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(	<09><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><16><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>	<09><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><14><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>iii<69><69><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>U<EFBFBD><55><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>eee<65><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>U<11><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>HHH<48><48><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><11><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>EEE<45><45><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>222<32>}}}<7D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><15><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>O<><4F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><50><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><06><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><06><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<><52><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Q<16><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>&<26><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>%U<><55><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>V	(Kj<4B><6A><EFBFBD><EFBFBD>jL(	<09>PNG

IHDR\r<>fsRGB<47><42><1C>8eXIfMM*<01>i<02><01>D"8sIDATx<01>]	<09>ՙn<D599>]<QVA<56><41><EFBFBD>h$	<09>N<EFBFBD><4E>13*<2A>q<EFBFBD><71>d<EFBFBD>č<>I<EFBFBD><49><08>D<EFBFBD>L2<4C><32>(<28>(Ԙ2<D498>ę<EFBFBD>G	<09><>q_@屈<><E5B188><EFBFBD>xț<>Џ<EFBFBD><D08F>{o<><6F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>U<EFBFBD>{}<7D>O<EFBFBD><4F>;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>9<EFBFBD>‘d<C291><64><EFBFBD>(Dg<44><13>8	<09><03>N<>]<5D><>@<0B>hx<>?v
<0A>N<EFBFBD>3<EFBFBD>=`;<3B>6<EFBFBD>.<2E>&<26><0B>u<EFBFBD><13>  <20><>6<06>P<><50>н<EFBFBD><D0BD>@<40>àR<C3A0>P<EFBFBD>iZq<>^DN<44><4E><1A>wp<77>
<0A><0C><01>X<EFBFBD>hИHg@<06><>
:<19><>|<08>5` p"@<03>'<27>ɲ<07>s{
<0A>p<EFBFBD>*<2A>2<EFBFBD><32><03><><EFBFBD> dү<64><D2AF><EFBFBD>|(0<12>
<0A>5<EFBFBD><35>
<0A><19><01><>ܶ<EFBFBD><DCB6><0C>;<3B>y<EFBFBD><79> <20>g<EFBFBD>s<04>h^I<><0C>DL(<28>;<13>8<1F><>Hjg<6A>cH|x<10>1<EFBFBD><31>R"<06>a<EFBFBD><61><EFBFBD>Ӂ<EFBFBD>G<EFBFBD><47>@<40><>9`/`%0<03>
H<>@j<0C>~,<2C><08><>K
<0A>,t).<06><01>I<EFBFBD><49><EFBFBD>D<18>T<EFBFBD>O<02>)~<7E><1C>V<03>u$b <0A>U%<25>7<EFBFBD><37><EFBFBD><EFBFBD><EFBFBD><EFBFBD>_<EFBFBD>$b 8A<38><41><EFBFBD><07><14><0E>J<EFBFBD>3` 510wQ<77>?<06><>vr<76><72><EFBFBD>:<3A>2<EFBFBD>K<EFBFBD>@ <06><>v*{%#<23><1A>A<EFBFBD>Z<EFBFBD>咁^(<28><>=<3D>g\<5C><>W<EFBFBD><57><01><11><04>!:<3A><>,`<1B>6<14><>643<>:@<40>c.Fٟ<03><><EFBFBD><EFBFBD>u?<11><<02><>'<27><14><07><><EFBFBD><EFBFBD>_܏vp: <20>8Q<><51>
I<>Ł<EFBFBD>
p{3<><33><EFBFBD>kHȢ<48>G<EFBFBD><47><02><><EFBFBD>c<EFBFBD>Ѽ
<<3C>62&<26>
<0A><05>
<0A><04><>;<3B><08><>d<EFBFBD>/~m<><6D>.<2E><>X<EFBFBD>@{<7B>w.<2E><1B>d]G<><47>{lK<6C><4B>Eb<03><><EFBFBD>(P<>RuM<75>T<EFBFBD>C<><43><EFBFBD><02>
<0A>d<EFBFBD><64>])<29><>_Lm<4C>=<3D><>=@b<03><><EFBFBD>K<EFBFBD><4B>GUk<55>^<5E>U<EFBFBD><06><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)1<><31><01><03>g<EFBFBD>T<EFBFBD>Š<EFBFBD><C28A>m`9<>\<03><EFBFBD><7F><EFBFBD>Q<EFBFBD><51>@<40><><EFBFBD><EFBFBD>Ⱆ6<E2B096><>^<02>w<EFBFBD><77><06><><01>E<EFBFBD>D<0C><><EFBFBD>	<09>5<EFBFBD><13><02><>F<03>,<2C><06>
<0A>X"<06>d<EFBFBD>m<EFBFBD><<3C>nB~<7E><>@<03><><EFBFBD><02>t<EFBFBD>t<EFBFBD>x<EFBFBD><78>
<0A>;<3B>f<EFBFBD>><3E><16><><1D>I8<49><02><><15>8<0E><06>C1۪$B<06><><13>e<EFBFBD><65><18>+<2B><>jl<><6C>EZ<03><11>& <20><>S:<3A>:<3A>6<EFBFBD>m<><6D><11><>\G1<1A><>`<60><><10>!<1E>nl<>l<EFBFBD>Ɗ<EFBFBD>^<5E>Q`<60><>@Oc<4F>S<EFBFBD><53>@e<06>ͷ<01><08><>qb<71>p<><70><04>S<><53>@up<><70><EFBFBD>F<EFBFBD>D@<40>Г<><D093><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2@#<23><><02><>L3<4C>A<EFBFBD><41>$H2<48>_h<04><07>FH#rq(<1C><>O<EFBFBD>D<EFBFBD>򤬈<EFBFBD><F2A4AC88><19>runGOWa<57>b<EFBFBD>&<26>SgD<03>3<EFBFBD>ED<45>to<74><><C7A4><EFBFBD><EFBFBD>9k<39><6B>~)<29><01><>,$<24>x<>R<>1<EFBFBD>v<0F>K <20><0F>9<EFBFBD>D䍁U(<28>w<01>&LE<4C><04><EFBFBD>S)<29><03>3<EFBFBD>Y8x8$.i<1A>(<28><>K<EFBFBD>ŀY<0C><><EFBFBD><EFBFBD>a<EFBFBD>]<5D><12><><0C>4<EFBFBD><34>ǀ	c<10><><EFBFBD><04>@3<06>f<EFBFBD><03><><12>4<EFBFBD>Ƣ<EFBFBD><C6A2>
<0A>/*b<><03><><EFBFBD><03><>$!I<1B>~<7E><0B>7<EFBFBD>B*-1`	o <20><13>	<13>$<24><>ǡD<C7A1><44><EFBFBD><EFBFBD><EFBFBD>L<EFBFBD><4C><01><18><03><><EFBFBD>J"<22><><18>OQ<4F><51>)<29><03>2@#<23>x4<78>"$e<><65><EFBFBD>I<>8<EFBFBD><38>Oi<4F><69>8<18>"<22><>G<><47>8[x<78>t<<14>.<07><>7&<26>m&؎R<D88E>^<5E><>tq<74>ؕ<EFBFBD>.<2E><><EFBFBD>Y<08>-2<><32>d<EFBFBD><0F><>*_<><06>&d|j\<5C>W<EFBFBD>b <20><0C>G<EFBFBD><47><01><>*g<><67><EFBFBD><EFBFBD><EFBFBD>F4<46>"I<>؃<>/b1q<19>N<EFBFBD><4E><EFBFBD><EFBFBD>Y<EFBFBD>D<0C><>p<0C><><EFBFBD>9<EFBFBD><39><EFBFBD>p<EFBFBD>}w\<5C><>Ԥ<EFBFBD><D4A4><EFBFBD>1 j`<60><03>O<><4F><1A>xK=<3D><>H<EFBFBD><48><EFBFBD>A<EFBFBD><41>1
<03>#<1A>
D:U8j<03><><EFBFBD>t<EFBFBD><74><EFBFBD>$b b<06>A||<15>U<>Q<EFBFBD><02>26%<25><>)1 <06><18>_
<0A>ꢳ!~D<><03><><EFBFBD><EFBFBD>+b >A<><41>:]<14>E$<24><>50<17><>GDhR<68>t<EFBFBD><74><EFBFBD><EFBFBD>ݻwR<77>)<29><>P<><16><>n$<24> 3<><33><EFBFBD>@bS<>Nu<4E>,Y<>j<EFBFBD>ʲ<EFBFBD><CAB2>:<3A><17><><EFBFBD>;<3B><08><><EFBFBD><EFBFBD>@<40>`<07>|<7C>-[)<29>'OV<4F><56>Ն<EFBFBD>sFxڮ<78><DAAE>ۥ<EFBFBD>n}͛7<CD9B><37><EFBFBD><EFBFBD><EFBFBD>~<7E><>ƺ<EFBFBD>:<01><><EFBFBD>Q<><51>J_<4A><5F>UKj8<6A>q0x<30><78><EFBFBD>;v4̞=[<5B>hW=<3D>	<09><>	<09>&<26>!e5<1A>8hѢE<D1A2><45>w<EFBFBD>]<5D><><EFBFBD><EFBFBD><EFBFBD>6<><36><EFBFBD>_<EFBFBD>iW}<7D>SZ<53>?	<09>/`<60>;vl<76>}<7D><>2<<3C>h<EFBFBD>"<19><0C><><EFBFBD>A<41>܁<14>X,<2C><6D>+V<>(<28><><<3C>w<EFBFBD><77><EFBFBD>#F<>^<5E><><EFBFBD>;<3B><><EFBFBD>aH<61>c<19><0C><>)S<>*<2A>{a<><61><EFBFBD>p<0B><08>c89(<28>^<5E><><EFBFBD><EFBFBD>4<EFBFBD>&E<><45><0A><>W<EFBFBD>/<2F><>u<EFBFBD>=<3D>^<5E><><EFBFBD>*?{k^<5E>_E<5F><45><EFBFBD><EFBFBD><EFBFBD>z<EFBFBD><05><>g<EFBFBD><02>UI-<2D><><EFBFBD>{WU*
<0A>:p<>9.tڷo(/ݺus><3E><>3<EFBFBD>'<27>^<5E>Rg<52><67><17>ڞG<DA9E><47>I_D<5F><44><EFBFBD><7F><0C><><EFBFBD>~~<7E><><05>{
<0A><08><>?N0<1F>7<EFBFBD>S<EFBFBD><53>.ƍ׸<D7B8>~?}/y]nA;<3B>أ<EFBFBD><D8A3><EFBFBD>2]<10>FOB2C?<3F>_I<5F><49><EFBFBD><EFBFBD>[<5B>:<03>:<3A>=#<23>OzK<7A>-<2D> <20><>ϣ<EFBFBD>%<0F><16><><EFBFBD>?j<03><11>I<06><><EFBFBD>P<EFBFBD>ۯ<EFBFBD><DBAF>{N<>-hU<68><55>t<>:<1B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><02>,<2C><1A><>G<EFBFBD>K<1E>-hU<68><55><06>c<EFBFBD>hP7 <07><><12>˜<EFBFBD>@<40>n?<3F>\<5C>-<2D>k<EFBFBD>.<2E><05><>2<EFBFBD>:<3A><> <20>`<14><>F<EFBFBD><46>=<3D>-<2D>V<EFBFBD>_<EFBFBD>G<EFBFBD><47>܂V<DC82><56><EFBFBD>}<7D>0WI<57><49><EFBFBD><EFBFBD>F<EFBFBD><46>ʭ<EFBFBD><CAAD><EFBFBD>sM<73>rZ<>8pJ<>Q<EFBFBD>*@OK8<08><><EFBFBD>
<0A>/V/<2F><>v<EFBFBD><02><><EFBFBD><EFBFBD><EFBFBD><0C><><08>*<2A>p<0E>v<EFBFBD><76><19><05><><11>ʟ]J<><4A>}<1B><>k8(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĉ<13>ѣGǗ<47>O<EFBFBD>mڴq,X<>o<0B><><EFBFBD>e.<0C>^ <20>Qx<1C><><EFBFBD>p<0E>t<EFBFBD><74><EFBFBD><04>4^_<1E>N<EFBFBD>{<7B><19><><EFBFBD><EFBFBD>y<EFBFBD>2<EFBFBD>s<EFBFBD><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-عsg<73>s<><73><07>i<EFBFBD>v<EFBFBD><76>Z
8
!~PJ?<3F>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>|<7C>]<5D>ܽ{<7B><>z<EFBFBD>긓R<EAB893><52>1pn<><6E><EFBFBD>z<EFBFBD><7A><EFBFBD><EFBFBD><13>tlp<>9<EFBFBD>f<EFBFBD>r<EFBFBD>v<EFBFBD>jT殿<54>z<07>4*O<>L<03>~<7E><><EFBFBD><1A>ԕ3<D495><33>4<EFBFBD>~~<7E>r<1A>;<3B>m<EFBFBD>xY<19>+<2B><><EFBFBD><0C><><1C><><EFBFBD><EFBFBD>3r<1A>;<3B>m<EFBFBD>x<EFBFBD>4<05><><EFBFBD>:7]ՁqL<>4)U<><55>!r<0B>1<EFBFBD><31>u<EFBFBD>6<EFBFBD><36><EFBFBD>$<24>
<0A>7<EFBFBD><37><EFBFBD><EFBFBD>8<06>w<EFBFBD><77>̙3Ǹ|5<>>?<3F>\z<><7A>O<EFBFBD><0C><>͆<EFBFBD><CD86><EFBFBD>,<2C>E<1D><><EFBFBD><EFBFBD>3<><33><07><><EFBFBD>2<EFBFBD><32><EFBFBD>[<5B><><EFBFBD><EFBFBD>2Wu:E<06><><EFBFBD><EFBFBD><EFBFBD>^p.H1cJ<63>t<>]}<7D><>B<>u<EFBFBD><75>SOu<4F><75><EFBFBD><EFBFBD><EFBFBD>Ic<>O<EFBFBD><4F><EFBFBD><EFBFBD><EFBFBD>%<25>
<1A>AZ<41><5A><EFBFBD><06><><EFBFBD>k<EFBFBD><6B><EFBFBD><EFBFBD>D?<3F>5<EFBFBD>@Q<><51>
<0A><><EFBFBD>3<EFBFBD>w<EFBFBD>+<2B><>"<22><>T<EFBFBD><03>S<EFBFBD><53><55>13<31><33>?<07><0B>5M'݋<><DD8B>>p<><06>Z<EFBFBD>j<EFBFBD>~fj<66>
׈<11>סԐ<D7A1>n<EFBFBD><6E><EFBFBD><EFBFBD><EFBFBD>><3E><><EFBFBD>i5D<35>[bf <20><>~a<>'<27>`Xc<><63><EFBFBD>-<2D>1<EFBFBD>k<EFBFBD><6B><01><>āI<C481><49><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k<EFBFBD><6B>Q<EFBFBD>ů|<7C>k<EFBFBD>M<EFBFBD><03>(92<39>@<40>t<18><><EFBFBD><EFBFBD><EFBFBD>݂X-<2D>Lדa<D793><61>N4<19><>qܞ'$f0@<40>
@V<>nA<6E>ܘY<DC98>L9:<3A>|/^s<><73><EFBFBD>	<09><>)0`<60>j<EFBFBD><6A>T\w<>uZ-<18><><EFBFBD><EFBFBD>¨\<03>	@<40>:<3A><>c<EFBFBD>t<EFBFBD><74><15>{<06>-<2D><>Rb<52><62>1%<25><>I,Y%T<><01><>~<0B><>r<0B>1<EFBFBD><31><EFBFBD><EFBFBD>C<EFBFBD><06>,<2C>$<24><><><CB80><EFBFBD>f<<3C><05>0z<30><7A><EFBFBD><01>h<>F<EFBFBD><46><EFBFBD><EFBFBD><EFBFBD><EFBFBD><15><>|<0B><13><>8Z-<2D>CR<43><52><EFBFBD><EFBFBD>Tg<54><67>HRf<52><66>glY<6C><17><><EFBFBD>s<EFBFBD><73>-<18><>p<EFBFBD><70>'+<10><><EFBFBD><EFBFBD>m<EFBFBD>_ؒg<D892><67><19><><14><>C<EFBFBD>{<7B>	<09><><01><>Ȫ<>ϏΙ3g<33>-<2D>GR|׹7`G<1A><>񥡘<EFBFBD>0<EFBFBD>U<EFBFBD><55>_ٵZЏ<5A>د<EFBFBD>D<03>)<29><><EFBFBD>\><3E><><EFBFBD><EFBFBD>ʗ<EFBFBD><CA97><15><05><18><>zN<03><><EFBFBD>@<40><>~~<7E><>-<2D><>P<EFBFBD><50>{rs<72><73><05>@<40><<3C><><EFBFBD><EFBFBD>|.]<5D>Ը|<7C><>m|g<><67><EFBFBD><EFBFBD>_<EFBFBD><5F>y<EFBFBD>W<EFBFBD>KD1<44>b<EFBFBD>M<EFBFBD><02><>%<25>s\<1C><17><><1F>r<0B>1<14><>n<EFBFBD>\<14>ƒ<>"-<2D><>`.4<EFBFBD><EFBFBD>~%3<><33>I}[0A<30><41>$<24><>=-<2D>>BH"G<>ۏ<EFBFBD>^r<><01><<3C>EBG<42>i<EFBFBD>%<25><><EFBFBD>9<EFBFBD>@^<5E>~~
@<40><05><18><><EFBFBD>1<EFBFBD><17><0B><>@<40>t<>-[<5B><><EFBFBD><EFBFBD>{%@C<>$<24>mAg<41><67><EFBFBD>Κ5kʆх<CA86><18><><EFBFBD>/双O<E58F8C><4F>l<EFBFBD><6C>ӿ<EFBFBD><D3BF>B<EFBFBD>@.X<><58><EFBFBD>u<17>p<EFBFBD>O<EFBFBD><4F>6<04><>x<EFBFBD>9MPn<50>`߷o_<6F><5F><EFBFBD>^n<>`t<>
S#<03>|^㽺- |<7C><>p<EFBFBD>
N<>.<2E><><EFBFBD>ޥ`<60>^{<7B>zL<7A>6<EFBFBD><36>4<EFBFBD>ě<EFBFBD>b<EFBFBD><62>e<EFBFBD>]&"<22>d<EFBFBD>sΜ9Uޥ<55>U0<55>!
<0A><>*nP<6E>*`<60><><EFBFBD>o֨v<D6A8><76><EFBFBD><EFBFBD>i8G<38><1A><><EFBFBD><EFBFBD>hh<><01>m<><6D><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɓ<EFBFBD>s<EFBFBD>=<3D>{J<>U0<55>Ղ<EFBFBD><D582><EFBFBD>wZ<77><5A><EFBFBD><15><><19><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>8bEz<><7A><EFBFBD>,Y<>D<EFBFBD><44>![C<>>}<7D><>7:k׮
<19>no<6E><6F>f<EFBFBD>>jvR?#b<><62>X<0C>(<28><>F<EFBFBD>AT<41>F<EFBFBD><46>i<EFBFBD><69>[<5B>{<7B><01>zv<7A><11>><3E><>C<EFBFBD><43><EFBFBD>a+<2B>[0B2<42>D<EFBFBD><44>=<3D><>G~<7E>(
&Lp8<70>'<27><><01><02><16><><EFBFBD><EFBFBD>4oGe<>#<23>ۏ<1F>lْ_\<5C>܂<CD80>2Z<32>l<17><>i<>9<EFBFBD><39>
t<>ȑ9f ޢ<>-<19><><01><>=<3D><><EFBFBD>Y<>y<EFBFBD><79>n?uQ<75>}<0C>sA<73>i>=<3D><>1<EFBFBD>=R<><52>+<2B> +
<0A>܂<EFBFBD><DC82>.2<EFBFBD><10>K<EFBFBD><0E><><EFBFBD><EFBFBD><EFBFBD>CƢۃ20h<30> <20>˫%53<35>5@<40>MA<4D>%<25><><03>̣<EFBFBD><CCA3><EFBFBD><17><><10>j[<5B><10>9<EFBFBD>;<3B><>_(<28><1F><><EFBFBD><EFBFBD>0<EFBFBD><30>~r<><72><EFBFBD>\<5C>{<7B>m<EFBFBD>P<EFBFBD><15><><EFBFBD>x#TT9<54><39>n?<3F><><EFBFBD><EFBFBD>N#<23><>ץ&<26>}<7D><><EFBFBD>)
<0A>T<18>VL<>!<21><><16>j<EFBFBD><6A><EFBFBD>`<0B>p
<0A>8@Rr<>UAV<41>A<EFBFBD><16><><EFBFBD>=<3D><>-<2D><><1A><>pLH<4C>`@n<>*Ȋ1<C88A>܂U<DC82><55><EFBFBD>?}w
]<02>H2@<40>ߴi<DFB4><02>V<EFBFBD><56><19>[<5B>˯%<25><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>5<EFBFBD>8<EFBFBD>)Э
T`<60><>|rZbZ-<18>.<2E>!da+@<40><><EFBFBD><EFBFBD>ߞ<>Z<EFBFBD>gf<03>[0p<30><70><EFBFBD><EFBFBD><1A><> I<06><>gr<0C>$<24><>o%P<>_rCy
<0A>V<EFBFBD><><DFBD><EFBFBD><19>"m<>Y<EFBFBD><13><>-<2D>[l<><03>kxA<78><15><>ۯ9]<5D>[pҤI<06>Ȩ<EFBFBD>pP<><50><EFBFBD>k<EFBFBD><6B>Feِ<65><D990><EFBFBD>gHE<48>d<EFBFBD>nAm"Z<>$<24><>5}<0B><><EFBFBD>z<EFBFBD>8<EFBFBD><38><EFBFBD><EFBFBD>2r<32>X<EFBFBD>|<7C> <20><>Sܻw<DCBB><77>r<EFBFBD>J<EFBFBD>s<EFBFBD>J<EFBFBD>~<7E>T<EFBFBD>f<EFBFBD>z{<7B>ͫ<EFBFBD><07>x<18>j?j<><6A>Q<EFBFBD>E<EFBFBD>n<EFBFBD><6E>js<03><><EFBFBD>|G<>xз<><dXt(<28><>Q<EFBFBD>E<EFBFBD>.<2E>p<>47<34><1B>)<29><><EFBFBD>;<3B><>ys<79>_<EFBFBD>V<EFBFBD>D<EFBFBD><44><0C>-XTi<54><69><EFBFBD><EFBFBD>?<3F><1B>~<7E><EFBFBD><E8969C><EFBFBD><EFBFBD><EFBFBD> <20>`Q<>=V<>?<3F><02><>^<5E>
<0A>m<EFBFBD>B~<7E><>?<02><><EFBFBD>J<EFBFBD><4A>D<EFBFBD><44><0B><><EFBFBD><EFBFBD><EFBFBD>~<7E>hr<16><><EFBFBD><EFBFBD><EFBFBD>ER<45><07><><41>B<EFBFBD><42><07>~w<>q<EFBFBD>Ӿ}<7D><><EFBFBD><<3C>ŕ[й5<>d<EFBFBD><64>-<2D>`<60>5?<1C>Kq<4B>~l4<6C><34>0@<40><>)<29><><EFBFBD><EFBFBD>/I<03><>(<15><><01><>؋<EFBFBD><D88B><EFBFBD>n<EFBFBD><6E>9<EFBFBD><39><EFBFBD>Y<EFBFBD>4<EFBFBD>!<21>Cو2ח*w9<03><><EFBFBD>GKݐ<4B>s<EFBFBD>&<26>r<EFBFBD>e<EFBFBD><65>s<EFBFBD><73>?<3F>6<EFBFBD>8J<38>|(<28>uwO䴁d<E4B481>&K)<29>nA<6E><41>?R<><52><EFBFBD>n@7,<2C><0C>8<>=<3D><><EFBFBD>r<EFBFBD>e<EFBFBD><65><0F><>n<EFBFBD>M<EFBFBD>69k<39><6B>M7<4D><37><EFBFBD><EFBFBD><EFBFBD>J<><4A>R<0F>]<5D>e<EFBFBD>n<EFBFBD><6E>9<EFBFBD><39><EFBFBD>Z<EFBFBD><5A><EFBFBD><EFBFBD> /?នo><3E><>󕾤<EFBFBD>rzr<><72> <20><>`<60><><EFBFBD>V{<7B><><EFBFBD>u<EFBFBD><75>4448<34>V<EFBFBD><56>ra<72><61>p<EFBFBD><70><EFBFBD>QRZ<52><{<7B>dK.F9<><39>#~T<><54><EFBFBD>s.<2E><><EFBFBD><EFBFBD>N%*<2A>
<0A><><EFBFBD>Ýu<C39D>8G&<26><><1A><0F>/W:*x%<25>{<7B>}@<40>
<0A><>l<04><><EFBFBD>Nc#<23>AI<41><49><EFBFBD><EFBFBD><EFBFBD><1E><>i<EFBFBD><69><EFBFBD><1E>*?<3F>د<07>0}<7D>g<EFBFBD><67><EFBFBD>C"Ā<70><DBAF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4ҏ(b<>8<>_Q<5F>Y<EFBFBD> <06><><EFBFBD>r7'<27><05><>`<60><><EFBFBD> <20>j<>6<EFBFBD><36> *<2A><03>3<EFBFBD>W<EFBFBD>g<EFBFBD><67>"<22><01>l<EFBFBD>
<12>ˆ1<>:<03>Sg}%<25> <20>	<01><>P?<3F><><EFBFBD><EFBFBD>1`<03><><EFBFBD><EFBFBD><07>Y<EFBFBD><1E><>"<22><>D<EFBFBD>0b@<0C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>9<EFBFBD><39><07><><EFBFBD><01>[t<><0F>F1<46><31><EFBFBD>p`k<>\U<>`<60><>R<EFBFBD><52>A#W81 e`)R<>ZM<5A><4D><EFBFBD><18><10>[u<><0F>F0<46>	rq.<2E><><EFBFBD><7F><EFBFBD>#^<0F>=C"Ā9P'<27>R~f<><66><1E>
pn<70>zdC"<06>e<EFBFBD><65><EFBFBD>?<3F>\K<0F><><EFBFBD><06>@&$b }jz<6A>3۵<33>x/{<0B><>1 Ra<52>#<23>|<7C><>ƟUK<55>=&<26>^<5E><>TM<54>n<03>2<EFBFBD>9<EFBFBD>5)?s<11><07><>{O'<27>D<0C><>D<19><><EFBFBD>o[kM<6B>oK0<4B>x<EFBFBD><78><EFBFBD>Td<54>_@]b r<06> <20>G<EFBFBD><47><1A><07><>;<3B><><EFBFBD><EFBFBD>D<0C><>D<18><><EFBFBD>1<EFBFBD>gaR<0B>`<60><>'`0<11>  <1A>>\<5C><>/<2F><><EFBFBD>f<10><1B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ŀ<18><><EFBFBD><EFBFBD>!fn<66>Z<>|b<><62><EFBFBD><EFBFBD>U<EFBFBD>.t<><14><03><><E0A49F><EFBFBD>r<01>9<1F>+<2B><><1E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>	<09>b rnE<6E>Dk<>=<3D><>8<EFBFBD><38><EFBFBD><EFBFBD><EFBFBD>!b R<06>Cl<43>P<>E<>`<60>܌<EFBFBD>K<EFBFBD>'~<7E>@<10><19><>}*<2A>!`<60>@<40><>6L<36>
<0A>;<3B><>	$b@D<><44>?#<23><>g<EFBFBD>F<EFBFBD>
<0A><><EFBFBD>8<>><3E><>p<>?vI<76><49>0<03>ǀ~<7E>!b<><62><EFBFBD><EFBFBD><EFBFBD><EFBFBD>$'<27>%"I<><49><EFBFBD><EFBFBD>R<EFBFBD><1D>i<EFBFBD>1 <06>0<EFBFBD><0B>?S~&<26><><18>r<EFBFBD><05><><0B><>{ n<1E>_<0C><><EFBFBD><17><>L<EFBFBD>?<3F><>T<06>e<EFBFBD><65>Ǝ<EFBFBD>7<EFBFBD>C"r<><72>OQ~"qI<71><49><EFBFBD>O8<>?$b <20>܋r<DC8B>#@<40>_<EFBFBD>v<17><4A><CC99>/<2F><03>3<EFBFBD>'d<>/<2F><><EFBFBD><EFBFBD>W[<5B><><01><>o'N<>
<0A>l<EFBFBD><0B>-2<><32><EFBFBD><EFBFBD>@j<>O~<7E><>0<0F><><EFBFBD>2`H<7F>@<40>؄<><0F>+<2B><><EFBFBD><EFBFBD>pOB<4F><42>uO<75><18>(l<>S<EFBFBD>ԕ<EFBFBD><D495><EFBFBD>9<08><><EFBFBD><EFBFBD>~<7E>c<07>:x/<2F>Xd<>.<2E><><1E>Ɣ<EFBFBD>d<EFBFBD><64>V<EFBFBD>y@F$H2<48><32><EFBFBD><EFBFBD><EFBFBD>+M*<2A>i<06><>l8O@F$H2<48><32><EFBFBD><1B>2<EFBFBD>4&r<>
PO<50><4F>֢<EFBFBD><D6A2>€<EFBFBD><C280>7N<37>YS
<0A><15><11><16>Y<EFBFBD>1`<1C><>;<3B>JS3n<33> g[<5B>'<27><>@W@"la`32<33>n?'<27>HB2p
<0A>hām<>mu <20><><EFBFBD><EFBFBD><10>j@F@<1C><>V<><56><EFBFBD><EFBFBD>Z!<21><>xI<78><49><EFBFBD>H<>y<>ѱ)<0C><19>><3E><0F>Z!6<12><17><>a<EFBFBD>`<60><><EFBFBD><EFBFBD><EFBFBD>dDV$9f<39><66><EFBFBD>	pM<70>6<EFBFBD>I<EFBFBD>!LG:\LdrwPy<50>~<7E>P<EFBFBD>%<25><>L3<06><>7<EFBFBD>TK<54><4B>Am<>mo|<7C>6<EFBFBD><36>	3<><1F>-<07>hJ3<4A><33>?<3F>67 <20>yr<79><72><01>"<22><><0B><0E>g<EFBFBD><67>4.$<24>1<EFBFBD><31><EFBFBD>_<0F>[*<2A><>&<06><><EFBFBD>S/<2F>dq<><01><><EFBFBD><EFBFBD><1E><>C<><03>h<EFBFBD>3<EFBFBD><33>><3E>6Ŷ%<25><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\<5C>#<23>RZq<10>
<0A>=lK|ŔX<C594><58>X<EFBFBD>WS<57>ej5/<2F><><EFBFBD><EFBFBD>$<24><><EFBFBD>:<3A><>v@<40><19><><EFBFBD><EFBFBD><13>8<EFBFBD><38>
<0A>d<EFBFBD><64>1(<28>z2~F<>)<29><13><>3<EFBFBD><33>͋<EFBFBD><CD8B><EFBFBD>l<EFBFBD><6C>C<EFBFBD><43><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>#<23><><EFBFBD><01>=<12>.\Lt? %<07>N$9b<39>%<25>:<11><><EFBFBD>2<04><>u	 <20>1|-<2D>	ld<08><><01><><EFBFBD>t$b<><62>@?<3F><><EFBFBD>@<40> <20>F<EFBFBD>c<EFBFBD><63>ρ^<5E>D<0C>d<EFBFBD>[9<>ࠐz<04><><EFBFBD><EFBFBD><EFBFBD>:
H<>@ <06><>P2v)~<7E><><EFBFBD>@<40><18><><EFBFBD>z5<7A><35>|<7C><><EFBFBD><13>R<EFBFBD>ֵ<EFBFBD><19><18>|`#<23>W39؂<39><D882><<0F>"-<03>0<EFBFBD><30>\<<01>d<0C><>u<EFBFBD>oGLz1<><03>Gp<0E><18><><EFBFBD>e<08>倯d<E580AF>.<2E>j
H<>@j<0C>F<EFBFBD>3<EFBFBD><33>@ c{s<<1D><>J&	<09>@<40><><EFBFBD><EFBFBD><EFBFBD>b<06><1D><19>w<EFBFBD><77> <20><> <20><>n<><6E><0E>v<EFBFBD><76>< <20><><19><><EFBFBD>,M;<3B><>*p>p!0hH<><19>{=<3D><><EFBFBD><EFBFBD><EFBFBD>x<11>]I<><0C>DLh<4C><68><EFBFBD><EFBFBD><'<27><>h8<>@V <20>#<23><>J<EFBFBD><08><06>f<1C>I<EFBFBD><0C><>Hn<48><6E><EFBFBD><EFBFBD>W<>}<0B>N<EFBFBD>t[u<06>$<24><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><15>
@<40> 2	<09>]&)<29><04>#<23>3<1A><><EFBFBD>,	=%<25>T<><54><EFBFBD>k<EFBFBD>&<26> I<><19><><EFBFBD><EFBFBD>I<EFBFBD><17>ӳ<EFBFBD><12>[8	<09>	<09>L<>]<5D>]t<>T<>g<EFBFBD><67><EFBFBD>6<EFBFBD>-@b2U<>OV<4F><56>:

A?<3F><>
}.i<>|	<09>xC<78><43><EFBFBD>rv<72>w;<3B><>#<23>><3E>i8_b82<>WP<57><50><EFBFBD><EFBFBD><EFBFBD><1A><>{'n<><6E><1C>8<EFBFBD>z;<3B>Ƥy<C6A4><EFBFBD>s<EFBFBD><73><EFBFBD>@<40><><08>P<><50>o|<7C>S<EFBFBD>ih$3<><33>j<><6A>IEND<4E>B`<60>
P<><50>н<EFBFBD><D0BD>@<40>àR<C3A0>P<EFBFBD>iZq<>^DN<44><4E><1A>wp<77>
<0A><0C><01>X<EFBFBD>hИHg@<06><>
:<19><>|<08>5` p"@<03>'<27>ɲ<07>s{
<0A>p<EFBFBD>*<2A>2<EFBFBD><32><03><><EFBFBD> dү<64><D2AF><EFBFBD>|(0<12>
0<><30>>K<>
<0A>xX<03>6IJ<0C><>C|?$KEN<01>}ϓ|<7C><><EFBFBD><EFBFBD><19><01>h $	2 <03><0C>|/<2F>.Nz<>#<0C><><EFBFBD>W<EFBFBD>e<EFBFBD>
<0A>5<EFBFBD><35>
<0A><19><01><>ܶ<EFBFBD><DCB6><0C>;<3B>y<EFBFBD><79> <20>g<EFBFBD>s<04>h^I<><0C>DL(<28>;<13>8<1F><>Hjg<6A>cH|x<10>1<EFBFBD><31>R"<06>a<EFBFBD><61><EFBFBD>Ӂ<EFBFBD>G<EFBFBD><47>@<40><>9`/`%0<03>
H<>@j<0C>~,<2C><08><>K
<0A>,t).<06><01>I<EFBFBD><49><EFBFBD>D<18>T<EFBFBD>O<02>)~<7E><1C>V<03>u$b <0A>U%<25>7<EFBFBD><37><EFBFBD><EFBFBD><EFBFBD><EFBFBD>_<EFBFBD>$b 8A<38><41><EFBFBD><07><14><0E>J<EFBFBD>3` 510wQ<77>?<06><>vr<76><72><EFBFBD>:<3A>2<EFBFBD>K<EFBFBD>@ <06><>v*{%#<23><1A>A<EFBFBD>Z<EFBFBD>咁^(<28><>=<3D>g\<5C><>W<EFBFBD><57><01><11><04>!:<3A><>,`<1B>6<14><>643<>:@<40>c.Fٟ<03><><EFBFBD><EFBFBD>u?<11><<02><>'<27><14><07><><EFBFBD><EFBFBD>_܏vp: <20>8Q<><51>
I<>Ł<EFBFBD>
p{3<><33><EFBFBD>kHȢ<48>G<EFBFBD><47><02><><EFBFBD>c<EFBFBD>Ѽ
<<3C>62&<26>
<0A><>2uC<75><43><05><><EFBFBD><EFBFBD><E695AD>T<1B>3<EFBFBD>
<0A><05>
<0A><04><>;<3B><08><>d<EFBFBD>/~m<><6D>.<2E><>X<EFBFBD>@{<7B>w.<2E><1B>d]G<><47>{lK<6C><4B>Eb<03><><EFBFBD>(P<>RuM<75>T<EFBFBD>C<><43><EFBFBD><02>
<0A>d<EFBFBD><64>])<29><>_Lm<4C>=<3D><>=@b<03><><EFBFBD>K<EFBFBD><4B>GUk<55>^<5E>U<EFBFBD><06><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)1<><31><01><03>g<EFBFBD>T<EFBFBD>Š<EFBFBD><C28A>m`9<>\<03><EFBFBD><7F><EFBFBD>Q<EFBFBD><51>@<40><><EFBFBD><EFBFBD>Ⱆ6<E2B096><>^<02>w<EFBFBD><77><06><><01>E<EFBFBD>D<0C><><EFBFBD>	<09>5<EFBFBD><13><02><>F<03>,<2C><06>
<0A>X"<06>d<EFBFBD>m<EFBFBD><<3C>nB~<7E><>@<03><><EFBFBD><02>t<EFBFBD>t<EFBFBD>x<EFBFBD><78>
<0A>;<3B>f<EFBFBD>><3E><16><><1D>I8<49><02><><15>8<0E><06>C1۪$B<06><><13>e<EFBFBD><65><18>+<2B><>jl<><6C>EZ<03><11>& <20><>S:<3A>:<3A>6<EFBFBD>m<><6D><11><>\G1<1A><>`<60><><10>!<1E>nl<>l<EFBFBD>Ɗ<EFBFBD>^<5E>Q`<60><>@Oc<4F>S<EFBFBD><53>@e<06>ͷ<01><08><>qb<71>p<><70><04>S<><53>@up<><70><EFBFBD>F<EFBFBD>D@<40>Г<><D093><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2@#<23><><02><>L3<4C>A<EFBFBD><41>$H2<48>_h<04><07>FH#rq(<1C><>O<EFBFBD>D<EFBFBD>򤬈<EFBFBD><F2A4AC88><19>runGOWa<57>b<EFBFBD>&<26>SgD<03>3<EFBFBD>ED<45>to<74><><C7A4><EFBFBD><EFBFBD>9k<39><6B>~)<29><01><>,$<24>x<>R<>1<EFBFBD>v<0F>K <20><0F>9<EFBFBD>D䍁U(<28>w<01>&LE<4C><04><EFBFBD>S)<29><03>3<EFBFBD>Y8x8$.i<1A>(<28><>K<EFBFBD>ŀY<0C><><EFBFBD><EFBFBD>a<EFBFBD>]<5D><12><><0C>4<EFBFBD><34>ǀ	c<10><><EFBFBD><04>@3<06>f<EFBFBD><03><><12>4<EFBFBD>Ƣ<EFBFBD><C6A2>
<0A>/*b<><03><><EFBFBD><03><>$!I<1B>~<7E><0B>7<EFBFBD>B*-1`	o <20><13>	<13>$<24><>ǡD<C7A1><44><EFBFBD><EFBFBD><EFBFBD>L<EFBFBD><4C><01><18><03><><EFBFBD>J"<22><><18>OQ<4F><51>)<29><03>2@#<23>x4<78>"$e<><65><EFBFBD>I<>8<EFBFBD><38>Oi<4F><69>8<18>"<22><>G<><47>8[x<78>t<<14>.<07><>7&<26>m&؎R<D88E>^<5E><>tq<74>ؕ<EFBFBD>.<2E><><EFBFBD>Y<08>-2<><32>d<EFBFBD><0F><>*_<><06>&d|j\<5C>W<EFBFBD>b <20><0C>G<EFBFBD><47><01><>*g<><67><EFBFBD><EFBFBD><EFBFBD>F4<46>"I<>؃<>/b1q<19>N<EFBFBD><4E><EFBFBD><EFBFBD>Y<EFBFBD>D<0C><>p<0C><><EFBFBD>9<EFBFBD><39><EFBFBD>p<EFBFBD>}w\<5C><>Ԥ<EFBFBD><D4A4><EFBFBD>1 j`<60><03>O<><4F><1A>xK=<3D><>H<EFBFBD><48><EFBFBD>A<EFBFBD><41>1
<03>#<1A>
D:U8j<03><><EFBFBD>t<EFBFBD><74><EFBFBD>$b b<06>A||<15>U<>Q<EFBFBD><02>26%<25><>)1 <06><18>_
<0A>ꢳ!~D<><03><><EFBFBD><EFBFBD>+b >A<><41>:]<14>E$<24><>50<17><>GDhR<68>t<EFBFBD><74><EFBFBD><EFBFBD>ݻwR<77>)<29><>P<><16><>n$<24> 3<><33><EFBFBD>@bS<>Nu<4E>,Y<>j<EFBFBD>ʲ<EFBFBD><CAB2>:<3A><17><><EFBFBD>;<3B><08><><EFBFBD><EFBFBD>@<40>`<07>|<7C>-[)<29>'OV<4F><56>Ն<EFBFBD>sFxڮ<78><DAAE>ۥ<EFBFBD>n}͛7<CD9B><37><EFBFBD><EFBFBD><EFBFBD>~<7E><>ƺ<EFBFBD>:<01><><EFBFBD>Q<><51>J_<4A><5F>UKj8<6A>q0x<30><78><EFBFBD>;v4̞=[<5B>hW=<3D>	<09><>	<09>&<26>!e5<1A>8hѢE<D1A2><45>w<EFBFBD>]<5D><><EFBFBD><EFBFBD><EFBFBD>6<><36><EFBFBD>_<EFBFBD>iW}<7D>SZ<53>?	<09>/`<60>;vl<76>}<7D><>2<<3C>h<EFBFBD>"<19><0C><><EFBFBD>A<41>܁<14>X,<2C><6D>+V<>(<28><><<3C>w<EFBFBD><77><EFBFBD>#F<>^<5E><><EFBFBD>;<3B><><EFBFBD>aH<61>c<19><0C><>)S<>*<2A>{a<><61><EFBFBD>p<0B><08>c89(<28>^<5E><><EFBFBD><EFBFBD>4<EFBFBD>&E<><45><0A><>W<EFBFBD>/<2F><>u<EFBFBD>=<3D>^<5E><><EFBFBD>*?{k^<5E>_E<5F><45><EFBFBD><EFBFBD><EFBFBD>z<EFBFBD><05><>g<EFBFBD><02>UI-<2D><><EFBFBD>{WU*
<0A>:p<>9.tڷo(/ݺus><3E><>3<EFBFBD>'<27>^<5E>Rg<52><67><17>ڞG<DA9E><47>I_D<5F><44><EFBFBD><7F><0C><><EFBFBD>~~<7E><><05>{
<0A><08><>?N0<1F>7<EFBFBD>S<EFBFBD><53>.ƍ׸<D7B8>~?}/y]nA;<3B>أ<EFBFBD><D8A3><EFBFBD>2]<10>FOB2C?<3F>_I<5F><49><EFBFBD><EFBFBD>[<5B>:<03>:<3A>=#<23>OzK<7A>-<2D> <20><>ϣ<EFBFBD>%<0F><16><><EFBFBD>?j<03><11>I<06><><EFBFBD>P<EFBFBD>ۯ<EFBFBD><DBAF>{N<>-hU<68><55>t<>:<1B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><02>,<2C><1A><>G<EFBFBD>K<1E>-hU<68><55><06>c<EFBFBD>hP7 <07><><12>˜<EFBFBD>@<40>n?<3F>\<5C>-<2D>k<EFBFBD>.<2E><05><>2<EFBFBD>:<3A><> <20>`<14><>F<EFBFBD><46>=<3D>-<2D>V<EFBFBD>_<EFBFBD>G<EFBFBD><47>܂V<DC82><56><EFBFBD>}<7D>0WI<57><49><EFBFBD><EFBFBD>F<EFBFBD><46>ʭ<EFBFBD><CAAD><EFBFBD>sM<73>rZ<>8pJ<>Q<EFBFBD>*@OK8<08><><EFBFBD>
rZ<><0B>ݖa,<2C><>w<EFBFBD><77>S<EFBFBD>W^y<><79><0E><>.<2E><>5<EFBFBD>at7<74><37>ݏ<EFBFBD><DD8F><EFBFBD>Tv#<23>~7n<0C><>A"<22><><EFBFBD><EFBFBD><EFBFBD>+<2B><>W<EFBFBD><13>pM<70><4D>/<01>hK8<4B><38><EFBFBD><EFBFBD>g<04><16>F/^<5E><0E><><EFBFBD><02><>M{e<><65>R<EFBFBD>|<7C>)q<><71>7<EFBFBD>t<EFBFBD><0E>?8'<27><1B><18>K<><4B>P~<7E><><EFBFBD><EFBFBD>\<5C><>r<0B><>><3E>ǷUk<55>eP<65><50>|<7C>^x<02><><EFBFBD><EFBFBD>
<0A>/V/<2F><>v<EFBFBD><02><><EFBFBD><EFBFBD><EFBFBD><0C><><08>*<2A>p<0E>v<EFBFBD><76><19><05><><11>ʟ]J<><4A>}<1B><>k8(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĉ<13>ѣGǗ<47>O<EFBFBD>mڴq,X<>o<0B><><EFBFBD>e.<0C>^ <20>Qx<1C><><EFBFBD>p<0E>t<EFBFBD><74><EFBFBD><04>4^_<1E>N<EFBFBD>{<7B><19><><EFBFBD><EFBFBD>y<EFBFBD>2<EFBFBD>s<EFBFBD><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-عsg<73>s<><73><07>i<EFBFBD>v<EFBFBD><76>Z
8
!~PJ?<3F>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>|<7C>]<5D>ܽ{<7B><>z<EFBFBD>긓R<EAB893><52>1pn<><6E><EFBFBD>z<EFBFBD><7A><EFBFBD><EFBFBD><13>tlp<>9<EFBFBD>f<EFBFBD>r<EFBFBD>v<EFBFBD>jT殿<54>z<07>4*O<>L<03>~<7E><><EFBFBD><1A>ԕ3<D495><33>4<EFBFBD>~~<7E>r<1A>;<3B>m<EFBFBD>xY<19>+<2B><><EFBFBD><0C><><1C><><EFBFBD><EFBFBD>3r<1A>;<3B>m<EFBFBD>x<EFBFBD>4<05><><EFBFBD>:7]ՁqL<>4)U<><55>!r<0B>1<EFBFBD><31>u<EFBFBD>6<EFBFBD><36><EFBFBD>$<24>
<0A>7<EFBFBD><37><EFBFBD><EFBFBD>8<06>w<EFBFBD><77>̙3Ǹ|5<>>?<3F>\z<><7A>O<EFBFBD><0C><>͆<EFBFBD><CD86><EFBFBD>,<2C>E<1D><><EFBFBD><EFBFBD>3<><33><07><><EFBFBD>2<EFBFBD><32><EFBFBD>[<5B><><EFBFBD><EFBFBD>2Wu:E<06><><EFBFBD><EFBFBD><EFBFBD>^p.H1cJ<63>t<>]}<7D><>B<>u<EFBFBD><75>SOu<4F><75><EFBFBD><EFBFBD><EFBFBD>Ic<>O<EFBFBD><4F><EFBFBD><EFBFBD><EFBFBD>%<25>
<1A>AZ<41><5A><EFBFBD><06><><EFBFBD>k<EFBFBD><6B><EFBFBD><EFBFBD>D?<3F>5<EFBFBD>@Q<><51>
<0A><><EFBFBD>3<EFBFBD>w<EFBFBD>+<2B><>"<22><>T<EFBFBD><03>S<EFBFBD><53><55>13<31><33>?<07><0B>5M'݋<><DD8B>>p<><06>Z<EFBFBD>j<EFBFBD>~fj<66>
׈<11>סԐ<D7A1>n<EFBFBD><6E><EFBFBD><EFBFBD><EFBFBD>><3E><><EFBFBD>i5D<35>[bf <20><>~a<>'<27>`Xc<><63><EFBFBD>-<2D>1<EFBFBD>k<EFBFBD><6B><01><>āI<C481><49><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k<EFBFBD><6B>Q<EFBFBD>ů|<7C>k<EFBFBD>M<EFBFBD><03>(92<39>@<40>t<18><><EFBFBD><EFBFBD><EFBFBD>݂X-<2D>Lדa<D793><61>N4<19><>qܞ'$f0@<40>
@V<>nA<6E>ܘY<DC98>L9:<3A>|/^s<><73><EFBFBD>	<09><>)0`<60>j<EFBFBD><6A>T\w<>uZ-<18><><EFBFBD><EFBFBD>¨\<03>	@<40>:<3A><>c<EFBFBD>t<EFBFBD><74><15>{<06>-<2D><>Rb<52><62>1%<25><>I,Y%T<><01><>~<0B><>r<0B>1<EFBFBD><31><EFBFBD><EFBFBD>C<EFBFBD><06>,<2C>$<24><><><CB80><EFBFBD>f<<3C><05>0z<30><7A><EFBFBD><01>h<>F<EFBFBD><46><EFBFBD><EFBFBD><EFBFBD><EFBFBD><15><>|<0B><13><>8Z-<2D>CR<43><52><EFBFBD><EFBFBD>Tg<54><67>HRf<52><66>glY<6C><17><><EFBFBD>s<EFBFBD><73>-<18><>p<EFBFBD><70>'+<10><><EFBFBD><EFBFBD>m<EFBFBD>_ؒg<D892><67><19><><14><>C<EFBFBD>{<7B>	<09><><01><>Ȫ<>ϏΙ3g<33>-<2D>GR|׹7`G<1A><>񥡘<EFBFBD>0<EFBFBD>U<EFBFBD><55>_ٵZЏ<5A>د<EFBFBD>D<03>)<29><><EFBFBD>\><3E><><EFBFBD><EFBFBD>ʗ<EFBFBD><CA97><15><05><18><>zN<03><><EFBFBD>@<40><>~~<7E><>-<2D><>P<EFBFBD><50>{rs<72><73><05>@<40><<3C><><EFBFBD><EFBFBD>|.]<5D>Ը|<7C><>m|g<><67><EFBFBD><EFBFBD>_<EFBFBD><5F>y<EFBFBD>W<EFBFBD>KD1<44>b<EFBFBD>M<EFBFBD><02><>%<25>s\<1C><17><><1F>r<0B>1<14><>n<EFBFBD>\<14>ƒ<>"-<2D><>`.4<EFBFBD><EFBFBD>~%3<><33>I}[0A<30><41>$<24><>=-<2D>>BH"G<>ۏ<EFBFBD>^r<><01><<3C>EBG<42>i<EFBFBD>%<25><><EFBFBD>9<EFBFBD>@^<5E>~~
@<40><05><18><><EFBFBD>1<EFBFBD><17><0B><>@<40>t<>-[<5B><><EFBFBD><EFBFBD>{%@C<>$<24>mAg<41><67><EFBFBD>Κ5kʆх<CA86><18><><EFBFBD>/双O<E58F8C><4F>l<EFBFBD><6C>ӿ<EFBFBD><D3BF>B<EFBFBD>@.X<><58><EFBFBD>u<17>p<EFBFBD>O<EFBFBD><4F>6<04><>x<EFBFBD>9MPn<50>`߷o_<6F><5F><EFBFBD>^n<>`t<>
<0A><>(<28><><EFBFBD><EFBFBD><EFBFBD>\r<><72>s<EFBFBD>A<EFBFBD>y<EFBFBD><79><EFBFBD>ۂ<EFBFBD>T<EFBFBD><0E>@h
<0A>E0l<30>0<EFBFBD><30>;<3B>tڵӘkƸN<C6B8><4E><EFBFBD><EFBFBD>Y<EFBFBD>jU<6A><55>
S#<03>|^㽺- |<7C><>p<EFBFBD>
N<>.<2E><><EFBFBD>ޥ`<60>^{<7B>zL<7A>6<EFBFBD><36>4<EFBFBD>ě<EFBFBD>b<EFBFBD><62>e<EFBFBD>]&"<22>d<EFBFBD>sΜ9Uޥ<55>U0<55>!
<0A><>*nP<6E>*`<60><><EFBFBD>o֨v<D6A8><76><EFBFBD><EFBFBD>i8G<38><1A><><EFBFBD><EFBFBD>hh<><01>m<><6D><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɓ<EFBFBD>s<EFBFBD>=<3D>{J<>U0<55>Ղ<EFBFBD><D582><EFBFBD>wZ<77><5A><EFBFBD><15><><19><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>8bEz<><7A><EFBFBD>,Y<>D<EFBFBD><44>![C<>>}<7D><>7:k׮
<19>no<6E><6F>f<EFBFBD>>jvR?#b<><62>X<0C>(<28><>F<EFBFBD>AT<41>F<EFBFBD><46>i<EFBFBD><69>[<5B>{<7B><01>zv<7A><11>><3E><>C<EFBFBD><43><EFBFBD>a+<2B>[0B2<42>D<EFBFBD><44>=<3D><>G~<7E>(
<06>ĺ<EFBFBD><C4BA><1B><><EFBFBD><EFBFBD>LO<1C>\s<>܂>"8|<7C>`[)
&Lp8<70>'<27><><01><02><16><><EFBFBD><EFBFBD>4oGe<>#<23>ۏ<1F>lْ_\<5C>܂<CD80>2Z<32>l<17><>i<>9<EFBFBD><39>
t<>ȑ9f ޢ<>-<19><><01><>=<3D><><EFBFBD>Y<>y<EFBFBD><79>n?uQ<75>}<0C>sA<73>i>=<3D><>1<EFBFBD>=R<><52>+<2B> +
<0A>܂<EFBFBD><DC82>.2<EFBFBD><10>K<EFBFBD><0E><><EFBFBD><EFBFBD><EFBFBD>CƢۃ20h<30> <20>˫%53<35>5@<40>MA<4D>%<25><><03>̣<EFBFBD><CCA3><EFBFBD><17><><10>j[<5B><10>9<EFBFBD>;<3B><>_(<28><1F><><EFBFBD><EFBFBD>0<EFBFBD><30>~r<><72><EFBFBD>\<5C>{<7B>m<EFBFBD>P<EFBFBD><15><><EFBFBD>x#TT9<54><39>n?<3F><><EFBFBD><EFBFBD>N#<23><>ץ&<26>}<7D><><EFBFBD>)
<0A>T<18>VL<>!<21><><16>j<EFBFBD><6A><EFBFBD>`<0B>p
<0A>8@Rr<>UAV<41>A<EFBFBD><16><><EFBFBD>=<3D><>-<2D><><1A><>pLH<4C>`@n<>*Ȋ1<C88A>܂U<DC82><55><EFBFBD>?}w
]<02>H2@<40>ߴi<DFB4><02>V<EFBFBD><56><19>[<5B>˯%<25><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>5<EFBFBD>8<EFBFBD>)Э
T`<60><>|rZbZ-<18>.<2E>!da+@<40><><EFBFBD><EFBFBD>ߞ<>Z<EFBFBD>gf<03>[0p<30><70><EFBFBD><EFBFBD><1A><> I<06><>gr<0C>$<24><>o%P<>_rCy
<0A>V<EFBFBD><><DFBD><EFBFBD><19>"m<>Y<EFBFBD><13><>-<2D>[l<><03>kxA<78><15><>ۯ9]<5D>[pҤI<06>Ȩ<EFBFBD>pP<><50><EFBFBD>k<EFBFBD><6B>Feِ<65><D990><EFBFBD>gHE<48>d<EFBFBD>nAm"Z<>$<24><>5}<0B><><EFBFBD>z<EFBFBD>8<EFBFBD><38><EFBFBD><EFBFBD>2r<32>X<EFBFBD>|<7C> <20><>Sܻw<DCBB><77>r<EFBFBD>J<EFBFBD>s<EFBFBD>J<EFBFBD>~<7E>T<EFBFBD>f<EFBFBD>z{<7B>ͫ<EFBFBD><07>x<18>j?j<><6A>Q<EFBFBD>E<EFBFBD>n<EFBFBD><6E>js<03><><EFBFBD>|G<>xз<><dXt(<28><>Q<EFBFBD>E<EFBFBD>.<2E>p<>47<34><1B>)<29><><EFBFBD>;<3B><>ys<79>_<EFBFBD>V<EFBFBD>D<EFBFBD><44><0C>-XTi<54><69><EFBFBD><EFBFBD>?<3F><1B>~<7E><EFBFBD><E8969C><EFBFBD><EFBFBD><EFBFBD> <20>`Q<>=V<>?<3F><02><>^<5E>
<0A><03><><16><><EFBFBD>.]<5D>|X<>
<0A>m<EFBFBD>B~<7E><>?<02><><EFBFBD>J<EFBFBD><4A>D<EFBFBD><44><0B><><EFBFBD><EFBFBD><EFBFBD>~<7E>hr<16><><EFBFBD><EFBFBD><EFBFBD>ER<45><07><><41>B<EFBFBD><42><07>~w<>q<EFBFBD>Ӿ}<7D><><EFBFBD><<3C>ŕ[й5<>d<EFBFBD><64>-<2D>`<60>5?<1C>Kq<4B>~l4<6C><34>0@<40><>)<29><><EFBFBD><EFBFBD>/I<03><>(<15><><01><>؋<EFBFBD><D88B><EFBFBD>n<EFBFBD><6E>9<EFBFBD><39><EFBFBD>Y<EFBFBD>4<EFBFBD>!<21>Cو2ח*w9<03><><EFBFBD>GKݐ<4B>s<EFBFBD>&<26>r<EFBFBD>e<EFBFBD><65>s<EFBFBD><73>?<3F>6<EFBFBD>8J<38>|(<28>uwO䴁d<E4B481>&K)<29>nA<6E><41>?R<><52><EFBFBD>n@7,<2C><0C>8<>=<3D><><EFBFBD>r<EFBFBD>e<EFBFBD><65><0F><>n<EFBFBD>M<EFBFBD>69k<39><6B>M7<4D><37><EFBFBD><EFBFBD><EFBFBD>J<><4A>R<0F>]<5D>e<EFBFBD>n<EFBFBD><6E>9<EFBFBD><39><EFBFBD>Z<EFBFBD><5A><EFBFBD><EFBFBD> /?នo><3E><>󕾤<EFBFBD>rzr<><72> <20><>`<60><><EFBFBD>V{<7B><><EFBFBD>u<EFBFBD><75>4448<34>V<EFBFBD><56>ra<72><61>p<EFBFBD><70><EFBFBD>QRZ<52><{<7B>dK.F9<><39>#~T<><54><EFBFBD>s.<2E><><EFBFBD><EFBFBD>N%*<2A>
<0A><><EFBFBD>Ýu<C39D>8G&<26><><1A><0F>/W:*x%<25>{<7B>}@<40>
<0A><>l<04><><EFBFBD>Nc#<23>AI<41><49><EFBFBD><EFBFBD><EFBFBD><1E><>i<EFBFBD><69><EFBFBD><1E>*?<3F>د<07>0}<7D>g<EFBFBD><67><EFBFBD>C"Ā<70><DBAF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4ҏ(b<>8<>_Q<5F>Y<EFBFBD> <06><><EFBFBD>r7'<27><05><>`<60><><EFBFBD> <20>j<>6<EFBFBD><36> *<2A><03>3<EFBFBD>W<EFBFBD>g<EFBFBD><67>"<22><01>l<EFBFBD>
<12>ˆ1<>:<03>Sg}%<25> <20>	<01><>P?<3F><><EFBFBD><EFBFBD>1`<03><><EFBFBD><EFBFBD><07>Y<EFBFBD><1E><>"<22><>D<EFBFBD>0b@<0C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>9<EFBFBD><39><07><><EFBFBD><01>[t<><0F>F1<46><31><EFBFBD>p`k<>\U<>`<60><>R<EFBFBD><52>A#W81 e`)R<>ZM<5A><4D><EFBFBD><18><10>[u<><0F>F0<46>	rq.<2E><><EFBFBD><7F><EFBFBD>#^<0F>=C"Ā9P'<27>R~f<><66><1E>
pn<70>zdC"<06>e<EFBFBD><65><EFBFBD>?<3F>\K<0F><><EFBFBD><06>@&$b }jz<6A>3۵<33>x/{<0B><>1 Ra<52>#<23>|<7C><>ƟUK<55>=&<26>^<5E><>TM<54>n<03>2<EFBFBD>9<EFBFBD>5)?s<11><07><>{O'<27>D<0C><>D<19><><EFBFBD>o[kM<6B>oK0<4B>x<EFBFBD><78><EFBFBD>Td<54>_@]b r<06> <20>G<EFBFBD><47><1A><07><>;<3B><><EFBFBD><EFBFBD>D<0C><>D<18><><EFBFBD>1<EFBFBD>gaR<0B>`<60><>'`0<11>  <1A>>\<5C><>/<2F><><EFBFBD>f<10><1B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ŀ<18><><EFBFBD><EFBFBD>!fn<66>Z<>|b<><62><EFBFBD><EFBFBD>U<EFBFBD>.t<><14><03><><E0A49F><EFBFBD>r<01>9<1F>+<2B><><1E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>	<09>b rnE<6E>Dk<>=<3D><>8<EFBFBD><38><EFBFBD><EFBFBD><EFBFBD>!b R<06>Cl<43>P<>E<>`<60>܌<EFBFBD>K<EFBFBD>'~<7E>@<10><19><>}*<2A>!`<60>@<40><>6L<36>
<0A>;<3B><>	$b@D<><44>?#<23><>g<EFBFBD>F<EFBFBD>
<0A><16>V<18><>1<10>v<><76>;<3B>Es<45><73>Q<EFBFBD><01><><EFBFBD><03>4<EFBFBD><34><EFBFBD>b@T<><54>n<EFBFBD><6E>!<10><>3q<>0^<5E>V<EFBFBD><56>c<EFBFBD><03>1<EFBFBD>ܶ<><DCB6>[<5B><><EFBFBD><15>M<EFBFBD>=8I<38><49><17><03>1@<40>څ@Cu<43><1D>`N<>o<EFBFBD><6F>W<08>W<EFBFBD><57><EFBFBD><EFBFBD>e<EFBFBD><65>I<EFBFBD><49>n<EFBFBD><6E>N<EFBFBD>mீ<6D><E0AF80>ܴ<>_d<><64>(<28>4`E܅I<DC85><49><0C><02><>1 *3<>+\<5C>E<EFBFBD> <20>\M<><15><>)g	r<><72><EFBFBD>
<0A><><EFBFBD>8<>><3E><>p<>?vI<76><49>0<03>ǀ~<7E>!b<><62><EFBFBD><EFBFBD><EFBFBD><EFBFBD>$'<27>%"I<><49><EFBFBD><EFBFBD>R<EFBFBD><1D>i<EFBFBD>1 <06>0<EFBFBD><0B>?S~&<26><><18>r<EFBFBD><05><><0B><>{ n<1E>_<0C><><EFBFBD><17><>L<EFBFBD>?<3F><>T<06>e<EFBFBD><65>Ǝ<EFBFBD>7<EFBFBD>C"r<><72>OQ~"qI<71><49><EFBFBD>O8<>?$b <20>܋r<DC8B>#@<40>_<EFBFBD>v<17><4A><CC99>/<2F><03>3<EFBFBD>'d<>/<2F><><EFBFBD><EFBFBD>W[<5B><><01><>o'N<>
<0A>l<EFBFBD><0B>-2<><32><EFBFBD><EFBFBD>@j<>O~<7E><>0<0F><><EFBFBD>2`H<7F>@<40>؄<><0F>+<2B><><EFBFBD><EFBFBD>pOB<4F><42>uO<75><18>(l<>S<EFBFBD>ԕ<EFBFBD><D495><EFBFBD>9<08><><EFBFBD><EFBFBD>~<7E>c<07>:x/<2F>Xd<>.<2E><><1E>Ɣ<EFBFBD>d<EFBFBD><64>V<EFBFBD>y@F$H2<48><32><EFBFBD><EFBFBD><EFBFBD>+M*<2A>i<06><>l8O@F$H2<48><32><EFBFBD><1B>2<EFBFBD>4&r<>
PO<50><4F>֢<EFBFBD><D6A2>€<EFBFBD><C280>7N<37>YS
<0A><15><11><16>Y<EFBFBD>1`<1C><>;<3B>JS3n<33> g[<5B>'<27><>@W@"la`32<33>n?'<27>HB2p
<0A>hām<>mu <20><><EFBFBD><EFBFBD><10>j@F@<1C><>V<><56><EFBFBD><EFBFBD>Z!<21><>xI<78><49><EFBFBD>H<>y<>ѱ)<0C><19>><3E><0F>Z!6<12><17><>a<EFBFBD>`<60><><EFBFBD><EFBFBD><EFBFBD>dDV$9f<39><66><EFBFBD>	pM<70>6<EFBFBD>I<EFBFBD>!LG:\LdrwPy<50>~<7E>P<EFBFBD>%<25><>L3<06><>7<EFBFBD>TK<54><4B>Am<>mo|<7C>6<EFBFBD><36>	3<><1F>-<07>hJ3<4A><33>?<3F>67 <20>yr<79><72><01>"<22><><0B><0E>g<EFBFBD><67>4.$<24>1<EFBFBD><31><EFBFBD>_<0F>[*<2A><>&<06><><EFBFBD>S/<2F>dq<><01><><EFBFBD><EFBFBD><1E><>C<><03>h<EFBFBD>3<EFBFBD><33>><3E>6Ŷ%<25><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\<5C>#<23>RZq<10>
<0A>=lK|ŔX<C594><58>X<EFBFBD>WS<57>ej5/<2F><><EFBFBD><EFBFBD>$<24><><EFBFBD>:<3A><>v@<40><19><><EFBFBD><EFBFBD><13>8<EFBFBD><38>
<0A>d<EFBFBD><64>1(<28>z2~F<>)<29><13><>3<EFBFBD><33>͋<EFBFBD><CD8B><EFBFBD>l<EFBFBD><6C>C<EFBFBD><43><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>#<23><><EFBFBD><01>=<12>.\Lt? %<07>N$9b<39>%<25>:<11><><EFBFBD>2<04><>u	 <20>1|-<2D>	ld<08><><01><><EFBFBD>t$b<><62>@?<3F><><EFBFBD>@<40> <20>F<EFBFBD>c<EFBFBD><63>ρ^<5E>D<0C>d<EFBFBD>[9<>ࠐz<04><><EFBFBD><EFBFBD><EFBFBD>:
H<>@ <06><>P2v)~<7E><><EFBFBD>@<40><18><><EFBFBD>z5<7A><35>|<7C><><EFBFBD><13>R<EFBFBD>ֵ<EFBFBD><19><18>|`#<23>W39؂<39><D882><<0F>"-<03>0<EFBFBD><30>\<<01>d<0C><>u<EFBFBD>oGLz1<><03>Gp<0E><18><><EFBFBD>e<08>倯d<E580AF>.<2E>j
H<>@j<0C>F<EFBFBD>3<EFBFBD><33>@ c{s<<1D><>J&	<09>@<40><><EFBFBD><EFBFBD><EFBFBD>b<06><1D><19>w<EFBFBD><77> <20><> <20><>n<><6E><0E>v<EFBFBD><76>< <20><><19><><EFBFBD>,M;<3B><>*p>p!0hH<><19>{=<3D><><EFBFBD><EFBFBD><EFBFBD>x<11>]I<><0C>DLh<4C><68><EFBFBD><EFBFBD><'<27><>h8<>@V <20>#<23><>J<EFBFBD><08><06>f<1C>I<EFBFBD><0C><>Hn<48><6E><EFBFBD><EFBFBD>W<>}<0B>N<EFBFBD>t[u<06>$<24><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><15>
@<40> 2	<09>]&)<29><04>#<23>3<1A><><EFBFBD>,	=%<25>T<><54><EFBFBD>k<EFBFBD>&<26> I<><19><><EFBFBD><EFBFBD>I<EFBFBD><17>ӳ<EFBFBD><12>[8	<09>	<09>L<>]<5D>]t<>T<>g<EFBFBD><67><EFBFBD>6<EFBFBD>-@b2U<>OV<4F><56>:

A?<3F><>
}.i<>|	<09>xC<78><43><EFBFBD>rv<72>w;<3B><>#<23>><3E>i8_b82<>WP<57><50><EFBFBD><EFBFBD><EFBFBD><1A><>{'n<><6E><1C>8<EFBFBD>z;<3B>Ƥy<C6A4><EFBFBD>s<EFBFBD><73><EFBFBD>@<40><><08>P<><50>o|<7C>S<EFBFBD>ih$3<><33>j<><6A>IEND<4E>B`<60>

src/app/globals.css

@import "tailwindcss";

:root {
  --background: #ffffff;
  --foreground: #171717;
}

@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
    "Liberation Mono", "Courier New", monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --background: #0a0a0a;
    --foreground: #ededed;
  }
}

body {
  background: var(--background);
  color: var(--foreground);
  font-family: var(--font-sans), Arial, Helvetica, sans-serif;
}

/* Animações suaves */
* {
  transition: colors 0.2s ease-in-out;
}

/* Scrollbar personalizada */
::-webkit-scrollbar {
  width: 8px;
}

::-webkit-scrollbar-track {
  background: #f1f5f9;
}

::-webkit-scrollbar-thumb {
  background: #cbd5e1;
  border-radius: 4px;
}

::-webkit-scrollbar-thumb:hover {
  background: #94a3b8;
}

/* Foco acessível */
input:focus {
  outline: none;
}

/* Animação de loading */
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.animate-spin {
  animation: spin 1s linear infinite;
}


src/app/laboratorios/page.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import LaboratorioForm from '@/components/LaboratorioForm';
import LaboratorioList from '@/components/LaboratorioList';
import { useLaboratorios, LaboratorioFormData } from '@/hooks/useLaboratorios';

const GestaoLaboratorios = () => {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [editing, setEditing] = useState<Models.Document | null>(null);
  const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
  const [searchTerm, setSearchTerm] = useState('');
  
  const {
    laboratorios,
    loading,
    error,
    totalLaboratorios,
    currentPage,
    listarLaboratorios,
    buscarLaboratorios,
    cadastrarLaboratorio,
    atualizarLaboratorio,
    deletarLaboratorio,
    setCurrentPage
  } = useLaboratorios();

  // 🔐 Verificar autenticação
  useEffect(() => {
    const initializeUser = async () => {
      try {
        const currentUser = await account.get();
        setUser(currentUser);
        
        if (activeTab === 'lista') {
          await listarLaboratorios();
        }
      } catch (error) {
        console.error('❌ Usuário não autenticado:', error);
        router.push('/');
      }
    };

    initializeUser();
  }, [activeTab, router, listarLaboratorios]);

  const handleFormSubmit = async (formData: LaboratorioFormData): Promise<boolean> => {
    if (editing) {
      const success = await atualizarLaboratorio(editing.$id, formData);
      if (success) {
        setEditing(null);
        setActiveTab('lista');
      }
      return success;
    } else {
      const success = await cadastrarLaboratorio(formData);
      if (success) {
        setTimeout(() => setActiveTab('lista'), 2000);
      }
      return success;
    }
  };

  const handleEdit = (lab: Models.Document) => {
    setEditing(lab);
    setActiveTab('cadastro');
  };

  const handleCancelEdit = () => {
    setEditing(null);
    setActiveTab('lista');
  };

  const handlePrevPage = async () => {
    if (currentPage > 1) {
      if (searchTerm.trim()) {
        await buscarLaboratorios(searchTerm, currentPage - 1);
      } else {
        await listarLaboratorios(currentPage - 1);
      }
    }
  };

  const handleSearch = async (term: string) => {
    setSearchTerm(term);
    if (term.trim()) {
      await buscarLaboratorios(term, 1);
    } else {
      await listarLaboratorios(1);
    }
  };

  const handleNextPage = async () => {
    const totalPages = Math.ceil(totalLaboratorios / 10);
    if (currentPage < totalPages) {
      if (searchTerm.trim()) {
        await buscarLaboratorios(searchTerm, currentPage + 1);
      } else {
        await listarLaboratorios(currentPage + 1);
      }
    }
  };

  if (!user) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
          <p className="text-gray-600">Verificando autenticação...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header 
        user={user} 
        title="Gestão de Laboratórios"
        subtitle="Gerencie os laboratórios da plataforma SaveInMed"
      />
      
      <main className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        {/* Navegação por Tabs */}
        <div className="mb-6">
          <nav className="flex space-x-8 bg-white p-4 rounded-lg shadow-sm">
            <button
              onClick={() => {
                setActiveTab('lista');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'lista'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
              📋 Listar Laboratórios
            </button>
            <button
              onClick={() => {
                setActiveTab('cadastro');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'cadastro'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
               Cadastrar Laboratório
            </button>
          </nav>
        </div>

        {/* Conteúdo das Tabs */}
        {activeTab === 'lista' && (
          <LaboratorioList
            laboratorios={laboratorios}
            loading={loading}
            error={error}
            totalLaboratorios={totalLaboratorios}
            currentPage={currentPage}
            pageSize={10}
            onEdit={handleEdit}
            onDelete={deletarLaboratorio}
            onRefresh={() =>
              searchTerm.trim()
                ? buscarLaboratorios(searchTerm, currentPage)
                : listarLaboratorios(currentPage)
            }
            onPrevPage={handlePrevPage}
            onNextPage={handleNextPage}
            onSearch={handleSearch}
          />
        )}

        {activeTab === 'cadastro' && (
          <LaboratorioForm
            onSubmit={handleFormSubmit}
            onCancel={editing ? handleCancelEdit : undefined}
            initialData={editing}
            loading={loading}
          />
        )}
      </main>
    </div>
  );
};

export default GestaoLaboratorios;


src/app/layout.tsx

import type { Metadata } from "next";
import "./globals.css";

export const metadata: Metadata = {
  title: "SaveInMed - Sistema de Gestão Médica",
  description: "Sistema inteligente para gestão médica e hospitalar",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="pt-BR">
      <body className="antialiased">
        {children}
      </body>
    </html>
  );
}


src/app/pagamentos/page.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import PagamentoForm from '@/components/PagamentoForm';
import PagamentoList from '@/components/PagamentoList';
import { usePagamentos } from '@/hooks/usePagamentos';
import { PagamentoData } from '@/services/pagamentoService';

const GestaoPagamentos = () => {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [editing, setEditing] = useState<Models.Document | null>(null);
  const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
  const [searchTerm, setSearchTerm] = useState('');

  const {
    pagamentos,
    loading,
    error,
    totalPagamentos,
    currentPage,
    listarPagamentos,
    cadastrarPagamento,
    atualizarPagamento,
    deletarPagamento,
  } = usePagamentos();

  useEffect(() => {
    const initializeUser = async () => {
      try {
        const currentUser = await account.get();
        setUser(currentUser);

        if (activeTab === 'lista') {
          await listarPagamentos(1, searchTerm);
        }
      } catch (error) {
        console.error('Usuário não autenticado:', error);
        router.push('/');
      }
    };

    initializeUser();
  }, [activeTab, router, listarPagamentos, searchTerm]);

  const handleFormSubmit = async (formData: PagamentoData): Promise<boolean> => {
    if (editing) {
      const success = await atualizarPagamento(editing.$id, formData);
      if (success) {
        setEditing(null);
        setActiveTab('lista');
      }
      return success;
    } else {
      const success = await cadastrarPagamento(formData);
      if (success) {
        setTimeout(() => setActiveTab('lista'), 2000);
      }
      return success;
    }
  };

  const handleEdit = (pag: Models.Document) => {
    setEditing(pag);
    setActiveTab('cadastro');
  };

  const handleCancelEdit = () => {
    setEditing(null);
    setActiveTab('lista');
  };

  const handleSearch = async (term: string) => {
    setSearchTerm(term);
    await listarPagamentos(1, term);
  };

  const handlePrevPage = async () => {
    if (currentPage > 1) {
      await listarPagamentos(currentPage - 1, searchTerm);
    }
  };

  const handleNextPage = async () => {
    const totalPages = Math.ceil(totalPagamentos / 10);
    if (currentPage < totalPages) {
      await listarPagamentos(currentPage + 1, searchTerm);
    }
  };

  if (!user) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
          <p className="text-gray-600">Verificando autenticação...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header
        user={user}
        title="Gestão de Pagamentos"
        subtitle="Gerencie os pagamentos da plataforma"
      />

      <main className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        <div className="mb-6">
          <nav className="flex space-x-8 bg-white p-4 rounded-lg shadow-sm">
            <button
              onClick={() => {
                setActiveTab('lista');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'lista'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
              📋 Listar Pagamentos
            </button>
            <button
              onClick={() => {
                setActiveTab('cadastro');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'cadastro'
### src/app/produtos/page.tsx
import React, { useEffect, useState } from 'react';
import { useProdutos, ProdutoData } from '@/hooks/useProdutos';
import ProdutoForm from '@/components/ProdutoForm';
import ProdutoList from '@/components/ProdutoList';
export default function ProdutosPage() {
    produtos,
    totalProdutos,
    listarProdutos,
    buscarProdutos,
    cadastrarProduto,
    atualizarProduto,
    deletarProduto,
  } = useProdutos();
  const [editDoc, setEditDoc] = useState<Models.Document | null>(null);
  const [searchTerm, setSearchTerm] = useState('');
  useEffect(() => {
    listarProdutos(currentPage, searchTerm);
  }, [currentPage, searchTerm]);
  const handleSave = async (data: ProdutoData) => {
    if (editDoc) {
      await atualizarProduto(editDoc.$id, data);
    } else {
      await cadastrarProduto(data);
    setEditDoc(null);
    listarProdutos(currentPage, searchTerm);
  const handleDelete = async (id: string) => {
    await deletarProduto(id);
    listarProdutos(currentPage, searchTerm);
  };

  const handleSearch = (term: string) => {
    setCurrentPage(1);
  const handleRefresh = () => {
    setSearchTerm('');
    setCurrentPage(1);
    <main className="container mx-auto px-4 py-8 space-y-8">
      <ProdutoForm
        initialData={editDoc}
        onSubmit={handleSave}
        onCancel={() => setEditDoc(null)}
        loading={loading}
      />
      {error && <p className="text-red-500">{error}</p>}
      <ProdutoList
        produtos={produtos}
        loading={loading}
        page={currentPage}
        total={totalProdutos}
        onEdit={setEditDoc}
        onDelete={handleDelete}
        onPrev={() => setCurrentPage(currentPage - 1)}
        onNext={() => setCurrentPage(currentPage + 1)}
        onSearch={handleSearch}
        onRefresh={handleRefresh}
      />
    </main>
}
### src/app/usuarios/page.tsx
import UsuarioForm from '@/components/UsuarioForm';
import UsuarioList from '@/components/UsuarioList';
import { useUsuarios, UsuarioFormData } from '@/hooks/useUsuarios';
const GestaoUsuarios = () => {

    usuarios,
    totalUsuarios,
    listarUsuarios,
    buscarUsuarios,
    cadastrarUsuario,
    atualizarUsuario,
    deletarUsuario,
    setCurrentPage,
  } = useUsuarios();
          await listarUsuarios();
  }, [activeTab, router, listarUsuarios]);
  const handleFormSubmit = async (formData: UsuarioFormData): Promise<boolean> => {
      const success = await atualizarUsuario(editing.$id, formData);
      const success = await cadastrarUsuario(formData);
  const handleEdit = (u: Models.Document) => {
    setEditing(u);

        await buscarUsuarios(searchTerm, currentPage - 1);
        await listarUsuarios(currentPage - 1);
      await buscarUsuarios(term, 1);
      await listarUsuarios(1);
    const totalPages = Math.ceil(totalUsuarios / 10);
        await buscarUsuarios(searchTerm, currentPage + 1);
        await listarUsuarios(currentPage + 1);
        title="Gestão de Usuários"
        subtitle="Gerencie os usuários da plataforma SaveInMed"
              📋 Listar Usuários
               Cadastrar Usuário
          <UsuarioList
            usuarios={usuarios}
            totalUsuarios={totalUsuarios}
            onDelete={deletarUsuario}
                ? buscarUsuarios(searchTerm, currentPage)
                : listarUsuarios(currentPage)
          <UsuarioForm
export default GestaoUsuarios;
### src/components/ActionButton.tsx
import React from 'react';
type ActionButtonVariant = 'edit' | 'delete' | 'view';
interface ActionButtonProps {
  variant: ActionButtonVariant;
  onClick: () => void;
  children: React.ReactNode;
  disabled?: boolean;
}
               Cadastrar Pedido
            </button>
          </nav>
        </div>

        {activeTab === 'lista' && (
          <PedidoList
            pedidos={pedidos}
            loading={loading}
            error={error}
            totalPedidos={totalPedidos}
            currentPage={currentPage}
            pageSize={10}
            onEdit={handleEdit}
            onDelete={deletarPedido}
            onRefresh={() => listarPedidos(currentPage, statusFilter, searchTerm)}
            onPrevPage={handlePrevPage}
            onNextPage={handleNextPage}
            onSearch={handleSearch}
            onFilterStatus={handleFilterStatus}
            statusOptions={statusOptions}
          />
        )}

        {activeTab === 'cadastro' && (
          <PedidoForm
            onSubmit={handleFormSubmit}
            onCancel={editing ? handleCancelEdit : undefined}
            initialData={editing}
            loading={loading}
            statusOptions={statusOptions}
          />
        )}
      </main>
    </div>
  );
};

export default GestaoPedidos;


src/app/produtos/page.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import ProdutoForm from '@/components/ProdutoForm';
import ProdutoList from '@/components/ProdutoList';
import { useProdutos, ProdutoData } from '@/hooks/useProdutos';

const GestaoProdutos = () => {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [editing, setEditing] = useState<Models.Document | null>(null);
  const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
  const [searchTerm, setSearchTerm] = useState('');

  const {
    produtos,
    loading,
    error,
    totalProdutos,
    currentPage,
    listarProdutos,
    buscarProdutos,
    cadastrarProduto,
    atualizarProduto,
    deletarProduto,
    setCurrentPage
  } = useProdutos();

  useEffect(() => {
    console.log('Produtos retornados:', produtos);
  }, [produtos]);

  useEffect(() => {
    const initializeUser = async () => {
      try {
        const currentUser = await account.get();
        setUser(currentUser);

        if (activeTab === 'lista') {
          await listarProdutos();
        }
      } catch (error) {
        console.error('❌ Usuário não autenticado:', error);
        router.push('/');
      }
    };

    initializeUser();
  }, [activeTab, router, listarProdutos]);

  const handleFormSubmit = async (formData: ProdutoData): Promise<boolean> => {
    if (editing) {
      const success = await atualizarProduto(editing.$id, formData);
      if (success) {
        setEditing(null);
        setActiveTab('lista');
      }
      return success;
    } else {
      const success = await cadastrarProduto(formData);
      if (success) {
        setTimeout(() => setActiveTab('lista'), 2000);
      }
      return success;
    }
  };

  const handleEdit = (prod: Models.Document) => {
    setEditing(prod);
    setActiveTab('cadastro');
  };

  const handleCancelEdit = () => {
    setEditing(null);
    setActiveTab('lista');
  };

  const handlePrevPage = async () => {
    if (currentPage > 1) {
      if (searchTerm.trim()) {
        await buscarProdutos(searchTerm, currentPage - 1);
      } else {
        await listarProdutos(currentPage - 1);
      }
    }
  };

  const handleSearch = async (term: string) => {
    setSearchTerm(term);
    if (term.trim()) {
      await buscarProdutos(term, 1);
    } else {
      await listarProdutos(1);
    }
  };

  const handleNextPage = async () => {
    const totalPages = Math.ceil(totalProdutos / 10);
    if (currentPage < totalPages) {
      if (searchTerm.trim()) {
        await buscarProdutos(searchTerm, currentPage + 1);
      } else {
        await listarProdutos(currentPage + 1);
      }
    }
  };

  if (!user) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
          <p className="text-gray-600">Verificando autenticação...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header
        user={user}
        title="Gestão de Produtos"
        subtitle="Gerencie os produtos da plataforma"
      />

      <main className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        <div className="mb-6">
          <nav className="flex space-x-8 bg-white p-4 rounded-lg shadow-sm">
            <button
              onClick={() => {
                setActiveTab('lista');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'lista'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
              📋 Listar Produtos
            </button>
            <button
              onClick={() => {
                setActiveTab('cadastro');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'cadastro'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
               Cadastrar Produto
            </button>
          </nav>
        </div>

        {activeTab === 'lista' && (
          <ProdutoList
            produtos={produtos}
            loading={loading}
            error={error}
            totalProdutos={totalProdutos}
            currentPage={currentPage}
            pageSize={10}
            onEdit={handleEdit}
            onDelete={deletarProduto}
            onRefresh={() =>
              searchTerm.trim()
                ? buscarProdutos(searchTerm, currentPage)
                : listarProdutos(currentPage)
            }
            onPrevPage={handlePrevPage}
            onNextPage={handleNextPage}
            onSearch={handleSearch}
          />
        )}

        {activeTab === 'cadastro' && (
          <ProdutoForm
            onSubmit={handleFormSubmit}
            onCancel={editing ? handleCancelEdit : undefined}
            initialData={editing}
            loading={loading}
          />
        )}
      </main>
    </div>
  );
};

export default GestaoProdutos;


src/app/usuarios/page.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import UsuarioForm from '@/components/UsuarioForm';
import UsuarioList from '@/components/UsuarioList';
import { useUsuarios, UsuarioFormData } from '@/hooks/useUsuarios';

const GestaoUsuarios = () => {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [editing, setEditing] = useState<Models.Document | null>(null);
  const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
  const [searchTerm, setSearchTerm] = useState('');

  const {
    usuarios,
    loading,
    error,
    totalUsuarios,
    currentPage,
    listarUsuarios,
    buscarUsuarios,
    cadastrarUsuario,
    atualizarUsuario,
    deletarUsuario,
    setCurrentPage,
  } = useUsuarios();

  useEffect(() => {
    const initializeUser = async () => {
      try {
        const currentUser = await account.get();
        setUser(currentUser);

        if (activeTab === 'lista') {
          await listarUsuarios();
        }
      } catch (error) {
        console.error('❌ Usuário não autenticado:', error);
        router.push('/');
      }
    };

    initializeUser();
  }, [activeTab, router, listarUsuarios]);

  const handleFormSubmit = async (formData: UsuarioFormData): Promise<boolean> => {
    if (editing) {
      const success = await atualizarUsuario(editing.$id, formData);
      if (success) {
        setEditing(null);
        setActiveTab('lista');
      }
      return success;
    } else {
      const success = await cadastrarUsuario(formData);
      if (success) {
        setTimeout(() => setActiveTab('lista'), 2000);
      }
      return success;
    }
  };

  const handleEdit = (u: Models.Document) => {
    setEditing(u);
    setActiveTab('cadastro');
  };

  const handleCancelEdit = () => {
    setEditing(null);
    setActiveTab('lista');
  };

  const handlePrevPage = async () => {
    if (currentPage > 1) {
      if (searchTerm.trim()) {
        await buscarUsuarios(searchTerm, currentPage - 1);
      } else {
        await listarUsuarios(currentPage - 1);
      }
    }
  };

  const handleSearch = async (term: string) => {
    setSearchTerm(term);
    if (term.trim()) {
      await buscarUsuarios(term, 1);
    } else {
      await listarUsuarios(1);
    }
  };

  const handleNextPage = async () => {
    const totalPages = Math.ceil(totalUsuarios / 10);
    if (currentPage < totalPages) {
      if (searchTerm.trim()) {
        await buscarUsuarios(searchTerm, currentPage + 1);
      } else {
        await listarUsuarios(currentPage + 1);
      }
    }
  };

  if (!user) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
          <p className="text-gray-600">Verificando autenticação...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header
        user={user}
        title="Gestão de Usuários"
        subtitle="Gerencie os usuários da plataforma SaveInMed"
      />

      <main className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        <div className="mb-6">
          <nav className="flex space-x-8 bg-white p-4 rounded-lg shadow-sm">
            <button
              onClick={() => {
                setActiveTab('lista');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'lista'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
              📋 Listar Usuários
            </button>
            <button
              onClick={() => {
                setActiveTab('cadastro');
                setEditing(null);
              }}
              className={`py-2 px-4 border-b-2 font-medium text-sm transition-colors cursor-pointer rounded-t-md ${
                activeTab === 'cadastro'
                  ? 'border-blue-500 text-blue-600 bg-blue-50'
                  : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
              }`}
            >
               Cadastrar Usuário
            </button>
          </nav>
        </div>

        {activeTab === 'lista' && (
          <UsuarioList
            usuarios={usuarios}
            loading={loading}
            error={error}
            totalUsuarios={totalUsuarios}
            currentPage={currentPage}
            pageSize={10}
            onEdit={handleEdit}
            onDelete={deletarUsuario}
            onRefresh={() =>
              searchTerm.trim()
                ? buscarUsuarios(searchTerm, currentPage)
                : listarUsuarios(currentPage)
            }
            onPrevPage={handlePrevPage}
            onNextPage={handleNextPage}
            onSearch={handleSearch}
          />
        )}

        {activeTab === 'cadastro' && (
          <UsuarioForm
            onSubmit={handleFormSubmit}
            onCancel={editing ? handleCancelEdit : undefined}
            initialData={editing}
            loading={loading}
          />
        )}
      </main>
    </div>
  );
};

export default GestaoUsuarios;


src/components/ActionButton.tsx

import React from 'react';

type ActionButtonVariant = 'edit' | 'delete' | 'view';

interface ActionButtonProps {
  variant: ActionButtonVariant;
  onClick: () => void;
  children: React.ReactNode;
  disabled?: boolean;
}

const ActionButton: React.FC<ActionButtonProps> = ({ 
  variant, 
  onClick, 
  children, 
  disabled = false 
}) => {
  const getVariantClasses = () => {
    switch (variant) {
      case 'edit':
        return 'bg-yellow-100 text-yellow-800 hover:bg-yellow-200';
      case 'delete':
        return 'bg-red-100 text-red-800 hover:bg-red-200';
      case 'view':
        return 'bg-blue-100 text-blue-800 hover:bg-blue-200';
      default:
        return 'bg-gray-100 text-gray-800 hover:bg-gray-200';
    }
  };

  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className={`
        rounded-md px-2 py-1 text-xs flex items-center gap-1 
        transition-all duration-200 hover:opacity-90
        disabled:opacity-50 disabled:cursor-not-allowed
        cursor-pointer
        ${getVariantClasses()}
      `}
    >
      {children}
    </button>
  );
};

export default ActionButton;

src/components/CarrinhoForm.tsx

import React, { useState, useEffect } from 'react';
import { Models } from 'appwrite';
import { CarrinhoFormData } from '@/hooks/useCarrinhos';
import { usuarioService } from '@/services/usuarioService';

interface CarrinhoFormProps {
  onSubmit: (data: CarrinhoFormData) => Promise<boolean>;
  onCancel?: () => void;
  initialData?: Models.Document | null;
  loading?: boolean;
}

const CarrinhoForm: React.FC<CarrinhoFormProps> = ({
  onSubmit,
  onCancel,
  initialData,
  loading = false
}) => {
  const [formData, setFormData] = useState<CarrinhoFormData>({
    usuarios: '',
    itens: [],
    quantidade: []
  });
  const [itemsText, setItemsText] = useState('');
  const [quantText, setQuantText] = useState('');
  const [usuariosList, setUsuariosList] = useState<Models.Document[]>([]);
  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);

  useEffect(() => {
    if (initialData) {
      setFormData({
        usuarios: (initialData as any).usuarios || '',
        itens: (initialData as any).itens || [],
        quantidade: (initialData as any).quantidade || []
      });
      setItemsText(((initialData as any).itens || []).join('\n'));
      setQuantText(((initialData as any).quantidade || []).join('\n'));
    } else {
      setFormData({ usuarios: '', itens: [], quantidade: [] });
      setItemsText('');
      setQuantText('');
    }
  }, [initialData]);

  useEffect(() => {
    const loadUsuarios = async () => {
      const res = await usuarioService.listar(1, 50);
      if (res.success) {
        setUsuariosList(res.documents);
      }
    };
    loadUsuarios();
  }, []);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    const itens = itemsText.split('\n').filter(i => i.trim() !== '');
    const quantidade = quantText
      .split('\n')
      .map(q => parseInt(q, 10))
      .filter(q => !isNaN(q));

    const success = await onSubmit({ ...formData, itens, quantidade });

    if (success) {
      setMessage({
        type: 'success',
        text: initialData ? '🔄 Carrinho atualizado com sucesso!' : '🎉 Carrinho cadastrado com sucesso!'
      });

      if (!initialData) {
        setFormData({ usuarios: '', itens: [], quantidade: [] });
        setItemsText('');
        setQuantText('');
      }

      setTimeout(() => setMessage(null), 3000);
    } else {
      setMessage({
        type: 'error',
        text: initialData ? 'Erro ao atualizar carrinho' : 'Erro ao cadastrar carrinho'
      });
    }
  };

  const handleInputChange = (
    e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
  ) => {
    const { name, value } = e.target;
    if (name === 'itens') {
      setItemsText(value);
    } else if (name === 'quantidade') {
      setQuantText(value);
    } else {
      setFormData(prev => ({ ...prev, [name]: value }));
    }
    if (message) setMessage(null);
  };

  return (
    <div className="bg-white rounded-lg shadow-md p-6">
      <div className="mb-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-2">
          {initialData ? '✏️ Editar Carrinho' : ' Novo Carrinho'}
        </h2>
        <p className="text-gray-600">
          {initialData ? 'Atualize os dados do carrinho.' : 'Cadastre um novo carrinho na plataforma SaveInMed.'}
        </p>
      </div>

      {message && (
        <div className={`mb-4 p-4 rounded-md ${
          message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'
        }`}>
          {message.text}
        </div>
      )}

      <form onSubmit={handleSubmit} className="space-y-6">
        <div>
          <label htmlFor="usuarios" className="block text-sm font-medium text-gray-700 mb-2">
            Usuário *
          </label>
          <select
            id="usuarios"
            name="usuarios"
            value={formData.usuarios}
            onChange={handleInputChange as any}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed text-gray-900 bg-white"
          >
            <option value="">Selecione...</option>
            {usuariosList.map(u => (
              <option key={u.$id} value={u.$id}>
                {(u as any)['nome-civil'] || u.$id}
              </option>
            ))}
          </select>
        </div>

        <div>
          <label htmlFor="itens" className="block text-sm font-medium text-gray-700 mb-2">
            Itens (um por linha)
          </label>
          <textarea
            id="itens"
            name="itens"
            value={itemsText}
            onChange={handleInputChange}
            disabled={loading}
            rows={4}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="Digite os itens do carrinho, um por linha"
          />
        </div>

        <div>
          <label htmlFor="quantidade" className="block text-sm font-medium text-gray-700 mb-2">
            Quantidades (uma por linha)
          </label>
          <textarea
            id="quantidade"
            name="quantidade"
            value={quantText}
            onChange={handleInputChange}
            disabled={loading}
            rows={4}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="Digite as quantidades correspondentes"
          />
        </div>

        <div className="flex gap-4">
          <button
            type="submit"
            disabled={loading || !formData.usuarios.trim()}
            className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
          >
            {loading ? '⏳ Processando...' : (initialData ? '🔄 Atualizar' : ' Cadastrar')}
          </button>

          {onCancel && (
            <button
              type="button"
              onClick={onCancel}
              disabled={loading}
              className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
            >
               Cancelar
            </button>
          )}
        </div>
      </form>
    </div>
  );
};

export default CarrinhoForm;


src/components/CarrinhoList.tsx

import React from 'react';
import { Models } from 'appwrite';
import SearchBar from './SearchBar';
import RefreshButton from './RefreshButton';
import ListHeader from './ListHeader';
import DataTable, { Column } from './DataTable';
import Pagination from './Pagination';
import ActionButton from './ActionButton';

interface Props {
  carrinhos: Models.Document[];
  loading: boolean;
  error: string | null;
  totalCarrinhos: number;
  currentPage: number;
  pageSize: number;
  onEdit: (doc: Models.Document) => void;
  onDelete: (id: string) => Promise<boolean>;
  onRefresh: () => void;
  onPrevPage: () => void;
  onNextPage: () => void;
  onSearch: (usuario: string) => void;
}

const columns: Column<Models.Document>[] = [
  {
    key: 'usuarios',
    header: 'Usuário',
    render: row => {
      const usuario = (row as any).usuarios;
      if (usuario && typeof usuario === 'object') {
        return (
          usuario['nome-civil'] || usuario['nome-social'] || usuario.$id || ''
        );
      }
      return usuario;
    }
  },
  {
    key: 'itens',
    header: 'Itens',
    render: row => ((row as any).itens || []).join(', ')
  },
  {
    key: 'quantidade',
    header: 'Quantidades',
    render: row => ((row as any).quantidade || []).join(', ')
  }
];

const CarrinhoList: React.FC<Props> = ({
  carrinhos,
  loading,
  error,
  totalCarrinhos,
  currentPage,
  pageSize,
  onEdit,
  onDelete,
  onRefresh,
  onPrevPage,
  onNextPage,
  onSearch
}) => {
  const totalPages = Math.ceil(totalCarrinhos / pageSize);
  const startItem = (currentPage - 1) * pageSize + 1;
  const endItem = Math.min(currentPage * pageSize, totalCarrinhos);
  const [search, setSearch] = React.useState('');

  const handleSearch = () => onSearch(search);
  const handleDelete = async (id: string) => {
    if (confirm('Tem certeza que deseja deletar este carrinho?')) {
      await onDelete(id);
    }
  };

  return (
    <div className="container mx-auto px-4 py-8">
      <ListHeader title="Lista de Carrinhos">
        <SearchBar
          value={search}
          onChange={setSearch}
          onSearch={handleSearch}
          placeholder="Buscar usuário"
        />
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
          {error}
        </div>
      )}

      {loading ? (
        <div className="flex justify-center items-center min-h-screen">
          <div className="text-lg">Carregando carrinhos...</div>
        </div>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={carrinhos}
            actions={row => (
              <>
                <ActionButton variant="edit" onClick={() => onEdit(row)}>
                  ✏️ Editar
                </ActionButton>
                <ActionButton variant="delete" onClick={() => handleDelete(row.$id)}>
                  🗑️ Deletar
                </ActionButton>
              </>
            )}
          />

          <div className="mt-4 flex justify-between items-center">
            <div className="text-sm text-gray-600">
              {totalCarrinhos > 0 ? (
                <>Mostrando {startItem} - {endItem} de {totalCarrinhos} carrinhos</>
              ) : (
                'Total de carrinhos: 0'
              )}
            </div>

            <Pagination page={currentPage} total={totalPages} onPrev={onPrevPage} onNext={onNextPage} />
          </div>
        </>
      )}
    </div>
  );
};

export default CarrinhoList;


src/components/CatalogoProdutoForm.tsx

import React, { useState, useEffect } from 'react';
import { Models } from 'appwrite';
import { CatalogoProdutoFormData } from '@/hooks/useCatalogoProdutos';

interface CatalogoProdutoFormProps {
  onSubmit: (data: CatalogoProdutoFormData) => Promise<boolean>;
  onCancel?: () => void;
  initialData?: Models.Document | null;
  loading?: boolean;
}

const CatalogoProdutoForm: React.FC<CatalogoProdutoFormProps> = ({
  onSubmit,
  onCancel,
  initialData,
  loading = false,
}) => {
  const [formData, setFormData] = useState<CatalogoProdutoFormData>({ nome: '' });
  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);

  useEffect(() => {
    if (initialData) {
      setFormData({ nome: initialData.nome });
    } else {
      setFormData({ nome: '' });
    }
  }, [initialData]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const success = await onSubmit(formData);
    if (success) {
      setMessage({
        type: 'success',
        text: initialData ? '🔄 Catálogo de produto atualizado com sucesso!' : '🎉 Catálogo de produto cadastrado com sucesso!'
      });
      if (!initialData) {
        setFormData({ nome: '' });
      }
      setTimeout(() => setMessage(null), 3000);
    } else {
      setMessage({ type: 'error', text: initialData ? 'Erro ao atualizar catálogo de produto' : 'Erro ao cadastrar catálogo de produto' });
    }
  };

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
    if (message) setMessage(null);
  };

  return (
    <div className="bg-white rounded-lg shadow-md p-6">
      <div className="mb-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-2">
          {initialData ? '✏️ Editar Catálogo de Produto' : ' Novo Catálogo de Produto'}
        </h2>
        <p className="text-gray-600">
          {initialData ? 'Atualize os dados do catálogo de produto.' : 'Cadastre um novo catálogo de produto na plataforma SaveInMed.'}
        </p>
      </div>

      {message && (
        <div className={`mb-4 p-4 rounded-md ${message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'}`}>
          {message.text}
        </div>
      )}

      <form onSubmit={handleSubmit} className="space-y-6">
        <div>
          <label htmlFor="nome" className="block text-sm font-medium text-gray-700 mb-2">
            Nome do Catálogo de Produto *
          </label>
          <input
            type="text"
            id="nome"
            name="nome"
            value={formData.nome}
            onChange={handleChange}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="Ex: Catálogo de Janeiro"
          />
        </div>
        <div className="flex gap-4">
          <button
            type="submit"
            disabled={loading}
            className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
          >
            {loading ? '⏳ Processando...' : initialData ? '🔄 Atualizar' : ' Cadastrar'}
          </button>
          {onCancel && (
            <button
              type="button"
              onClick={onCancel}
              disabled={loading}
              className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
            >
               Cancelar
            </button>
          )}
        </div>
      </form>
    </div>
  );
};

export default CatalogoProdutoForm;


src/components/CatalogoProdutosList.tsx

import React from 'react';
import { Models } from 'appwrite';
import SearchBar from './SearchBar';
import RefreshButton from './RefreshButton';
import ListHeader from './ListHeader';
import DataTable, { Column } from './DataTable';
import Pagination from './Pagination';
import ActionButton from './ActionButton';

interface CatalogoProdutosListProps {
  catalogoProdutos: Models.Document[];
  loading: boolean;
  error: string | null;
  totalCatalogoProdutos: number;
  currentPage: number;
  pageSize: number;
  onEdit: (catalogoProduto: Models.Document) => void;
  onDelete: (id: string) => Promise<boolean>;
  onRefresh: () => void;
  onPrevPage: () => void;
  onNextPage: () => void;
  onSearch: (nome: string) => void;
}

const CatalogoProdutosList: React.FC<CatalogoProdutosListProps> = ({
  catalogoProdutos,
  loading,
  error,
  totalCatalogoProdutos,
  currentPage,
  pageSize,
  onEdit,
  onDelete,
  onRefresh,
  onPrevPage,
  onNextPage,
  onSearch
}) => {
  const totalPages = Math.ceil(totalCatalogoProdutos / pageSize);
  const startItem = (currentPage - 1) * pageSize + 1;
  const endItem = Math.min(currentPage * pageSize, totalCatalogoProdutos);

  const [search, setSearch] = React.useState('');

  React.useEffect(() => {
    console.log('📦 [FRONT] Catálogo de produtos listado:', catalogoProdutos);
  }, [catalogoProdutos]);

  const handleSearch = () => {
    onSearch(search);
  };

  const handleDelete = async (id: string) => {
    if (confirm('Tem certeza que deseja deletar este catálogo de produto?')) {
      await onDelete(id);
    }
  };

  const columns: Column<Models.Document>[] = [
    { key: 'nome', header: 'Nome' },
    { key: '$id', header: 'ID' },
    { key: '$createdAt', header: 'Data de Criação', render: row => new Date(row.$createdAt).toLocaleDateString('pt-BR') },
  ];

  return (
    <div className="container mx-auto px-4 py-8">
      <ListHeader title="Lista de Catálogo de Produtos">
        <SearchBar
          value={search}
          onChange={setSearch}
          onSearch={handleSearch}
          placeholder="Buscar catálogo de produto"
        />
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
          {error}
        </div>
      )}

      {loading ? (
        <div className="flex justify-center items-center min-h-screen">
          <div className="text-lg">Carregando catálogos de produtos...</div>
        </div>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={catalogoProdutos}
            actions={(catalogoProduto) => (
              <>
                <ActionButton
                  variant="edit"
                  onClick={() => onEdit(catalogoProduto)}
                >
                  ✏️ Editar
                </ActionButton>
                <ActionButton
                  variant="delete"
                  onClick={() => handleDelete(catalogoProduto.$id)}
                >
                  🗑️ Deletar
                </ActionButton>
              </>
            )}
          />

          <div className="mt-4 flex justify-between items-center">
            <div className="text-sm text-gray-600">
              {totalCatalogoProdutos > 0 ? (
                <>Mostrando {startItem} - {endItem} de {totalCatalogoProdutos} catálogos de produtos</>
              ) : (
                'Total de catálogos de produtos: 0'
              )}
            </div>

            <Pagination
              page={currentPage}
              total={totalPages}
              onPrev={onPrevPage}
              onNext={onNextPage}
            />
          </div>
        </>
      )}
    </div>
  );
};

export default CatalogoProdutosList;



src/components/CategoriaForm.tsx

import React, { useState, useEffect } from 'react';
import { Models } from 'appwrite';
import { CategoriaFormData } from '@/hooks/useCategorias';

interface CategoriaFormProps {
  onSubmit: (data: CategoriaFormData) => Promise<boolean>;
  onCancel?: () => void;
  initialData?: Models.Document | null;
  loading?: boolean;
}

const CategoriaForm: React.FC<CategoriaFormProps> = ({
  onSubmit,
  onCancel,
  initialData,
  loading = false
}) => {
  const [formData, setFormData] = useState<CategoriaFormData>({
    nome: ''
  });
  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);

  useEffect(() => {
    if (initialData) {
      setFormData({ nome: initialData.nome || '' });
    } else {
      setFormData({ nome: '' });
    }
  }, [initialData]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    const success = await onSubmit(formData);
    
    if (success) {
      setMessage({ 
        type: 'success', 
        text: initialData ? '🔄 Categoria atualizada com sucesso!' : '🎉 Categoria cadastrada com sucesso!'
      });
      
      if (!initialData) {
        setFormData({ nome: '' });
      }
      
      setTimeout(() => setMessage(null), 3000);
    } else {
      setMessage({ 
        type: 'error', 
        text: initialData ? 'Erro ao atualizar categoria' : 'Erro ao cadastrar categoria'
      });
    }
  };

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
    if (message) setMessage(null);
  };

  return (
    <div className="bg-white rounded-lg shadow-md p-6">
      <div className="mb-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-2">
          {initialData ? '✏️ Editar Categoria' : ' Nova Categoria'}
        </h2>
        <p className="text-gray-600">
          {initialData ? 'Atualize os dados da categoria.' : 'Cadastre uma nova categoria na plataforma SaveInMed.'}
        </p>
      </div>

      {message && (
        <div className={`mb-4 p-4 rounded-md ${
          message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'
        }`}>
          {message.text}
        </div>
      )}

      <form onSubmit={handleSubmit} className="space-y-6">
        <div>
          <label htmlFor="nome" className="block text-sm font-medium text-gray-700 mb-2">
            Nome da Categoria *
          </label>
          <input
            type="text"
            id="nome"
            name="nome"
            value={formData.nome}
            onChange={handleInputChange}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed text-gray-900 bg-white"
            placeholder="Digite o nome da categoria"
          />
        </div>

        <div className="flex gap-4">
          <button
            type="submit"
            disabled={loading || !formData.nome.trim()}
            className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
          >
            {loading ? '⏳ Processando...' : (initialData ? '🔄 Atualizar' : ' Cadastrar')}
          </button>
          
          {onCancel && (
            <button
              type="button"
              onClick={onCancel}
              disabled={loading}
              className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
            >
               Cancelar
            </button>
          )}
        </div>
      </form>
    </div>
  );
};

export default CategoriaForm;

src/components/CategoriaList.tsx

import React from 'react';
import { Models } from 'appwrite';
import SearchBar from './SearchBar';
import RefreshButton from './RefreshButton';
import ListHeader from './ListHeader';
import DataTable, { Column } from './DataTable';
import Pagination from './Pagination';
import ActionButton from './ActionButton';

interface CategoriaListProps {
  categorias: Models.Document[];
  loading: boolean;
  error: string | null;
  totalCategorias: number;
  currentPage: number;
  pageSize: number;
  onEdit: (lab: Models.Document) => void;
  onDelete: (id: string) => Promise<boolean>;
  onRefresh: () => void;
  onPrevPage: () => void;
  onNextPage: () => void;
  onSearch: (nome: string) => void;
}

const CategoriaList: React.FC<CategoriaListProps> = ({
  categorias,
  loading,
  error,
  totalCategorias,
  currentPage,
  pageSize,
  onEdit,
  onDelete,
  onRefresh,
  onPrevPage,
  onNextPage,
  onSearch
}) => {
  const totalPages = Math.ceil(totalCategorias / pageSize);
  const startItem = (currentPage - 1) * pageSize + 1;
  const endItem = Math.min(currentPage * pageSize, totalCategorias);

  const [search, setSearch] = React.useState('');

  const handleSearch = () => {
    onSearch(search);
  };

  const handleDelete = async (id: string) => {
    if (confirm('Tem certeza que deseja deletar esta categoria?')) {
      await onDelete(id);
    }
  };

  const columns: Column<Models.Document>[] = [
    { key: 'nome', header: 'Nome' },
    { key: '$id', header: 'ID' },
    { key: '$createdAt', header: 'Data de Criação', render: row => new Date(row.$createdAt).toLocaleDateString('pt-BR') },
  ];

  return (
    <div className="container mx-auto px-4 py-8">
      <ListHeader title="Lista de Categorias">
        <SearchBar
          value={search}
          onChange={setSearch}
          onSearch={handleSearch}
          placeholder="Buscar categoria"
        />
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
          {error}
        </div>
      )}

      {loading ? (
        <div className="flex justify-center items-center min-h-screen">
          <div className="text-lg">Carregando categorias...</div>
        </div>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={categorias}
            actions={(lab) => (
              <>
                <ActionButton
                  variant="edit"
                  onClick={() => onEdit(lab)}
                >
                  ✏️ Editar
                </ActionButton>
                <ActionButton
                  variant="delete"
                  onClick={() => handleDelete(lab.$id)}
                >
                  🗑️ Deletar
                </ActionButton>
              </>
            )}
          />

          <div className="mt-4 flex justify-between items-center">
            <div className="text-sm text-gray-600">
              {totalCategorias > 0 ? (
                <>Mostrando {startItem} - {endItem} de {totalCategorias} categorias</>
              ) : (
                'Total de categorias: 0'
              )}
            </div>

            <Pagination
              page={currentPage}
              total={totalPages}
              onPrev={onPrevPage}
              onNext={onNextPage}
            />
          </div>
        </>
      )}
    </div>
  );
};

export default CategoriaList;

src/components/DataTable.tsx

import React from 'react';

export interface Column<T> {
  key: string;
  header: string;
  render?: (row: T) => React.ReactNode;
}

type Props<T> = {
  columns: Column<T>[];
  data: T[];
  actions?: (row: T) => React.ReactNode;
};

function DataTable<T>({ columns, data, actions }: Props<T>) {
  return (
    <div className="bg-white shadow-md rounded-lg overflow-hidden border border-gray-200">
      <table className="min-w-full table-auto">
        <thead className="bg-gray-50">
          <tr>
            {columns.map(col => (
              <th
                key={col.key}
                className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider border-b border-gray-200"
              >
                {col.header}
              </th>
            ))}
            {actions && (
              <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider border-b border-gray-200">
                Ações
              </th>
            )}
          </tr>
        </thead>
        <tbody className="divide-y divide-gray-200">
          {data.length === 0 ? (
            <tr>
              <td
                colSpan={columns.length + (actions ? 1 : 0)}
                className="px-6 py-4 text-center text-gray-500"
              >
                📭 Nenhum item encontrado.
              </td>
            </tr>
          ) : (
            data.map((row, idx) => (
              <tr key={idx} className="odd:bg-gray-50 hover:bg-gray-100 transition-colors duration-150 border-b border-gray-200">
                {columns.map(col => (
                  <td key={col.key} className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">
                    {(function () {
                      const value = col.render ? col.render(row) : (row as any)[
                        col.key
                      ];
                      return typeof value === 'object' && value !== null
                        ? JSON.stringify(value)
                        : value;
                    })()}
                  </td>
                ))}
                {actions && (
                  <td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
                    <div className="flex gap-2">
                      {actions(row)}
                    </div>
                  </td>
                )}
              </tr>
            ))
          )}
        </tbody>
      </table>
    </div>
  );
}

export default DataTable;


src/components/EmpresaList.tsx

import React from 'react';
import { Models } from 'appwrite';
import SearchBar from './SearchBar';
import RefreshButton from './RefreshButton';
import ListHeader from './ListHeader';
import DataTable, { Column } from './DataTable';
import Pagination from './Pagination';
import ActionButton from './ActionButton';

interface EmpresaListProps {
  empresas: Models.Document[];
  loading: boolean;
  error: string | null;
  onEdit: (empresa: Models.Document) => void;
  onDelete: (id: string) => Promise<boolean>;
  onRefresh: () => void;
}

const EmpresaList: React.FC<EmpresaListProps> = ({
  empresas,
  loading,
  error,
  onEdit,
  onDelete,
  onRefresh,
}) => {
  const [search, setSearch] = React.useState('');

  const handleSearch = () => {
    // Apenas visual; lógica de busca não implementada
  };

  const handleDelete = async (id: string) => {
    if (confirm('Tem certeza que deseja deletar esta empresa?')) {
      await onDelete(id);
    }
  };

  const columns: Column<Models.Document>[] = [
    { key: 'nome-fantasia', header: 'Nome Fantasia' },
    { key: 'razao-social', header: 'Razão Social' },
    { key: 'cnpj', header: 'CNPJ' },
    { key: '$id', header: 'ID' },
  ];

  const totalEmpresas = empresas.length;

  return (
    <div className="container mx-auto px-4 py-8">
      <ListHeader title="Lista de Empresas">
        <SearchBar
          value={search}
          onChange={setSearch}
          onSearch={handleSearch}
          placeholder="Buscar empresa"
        />
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
          {error}
        </div>
      )}

      {loading ? (
        <div className="flex justify-center items-center min-h-screen">
          <div className="text-lg">Carregando empresas...</div>
        </div>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={empresas}
            actions={(empresa) => (
              <>
                <ActionButton variant="edit" onClick={() => onEdit(empresa)}>
                  ✏️ Editar
                </ActionButton>
                <ActionButton variant="delete" onClick={() => handleDelete(empresa.$id)}>
                  🗑️ Excluir
                </ActionButton>
              </>
            )}
          />

          <div className="mt-4 flex justify-between items-center">
            <div className="text-sm text-gray-600">
              {totalEmpresas > 0 ? (
                <>Mostrando 1 - {totalEmpresas} de {totalEmpresas} empresas</>
              ) : (
                'Total de empresas: 0'
              )}
            </div>
            <Pagination page={1} total={1} onPrev={() => {}} onNext={() => {}} />
          </div>
        </>
      )}
    </div>
  );
};

export default EmpresaList;


src/components/EnderecoForm.tsx

import React, { useState, useEffect } from 'react';
import { Models } from 'appwrite';
import { EnderecoData } from '@/services/enderecoService';

interface EnderecoFormProps {
  onSubmit: (data: EnderecoData) => Promise<boolean>;
  onCancel?: () => void;
  initialData?: Models.Document | null;
  loading?: boolean;
}

const EnderecoForm: React.FC<EnderecoFormProps> = ({
  onSubmit,
  onCancel,
  initialData,
  loading = false
}) => {
  const [formData, setFormData] = useState<EnderecoData>({
    titulo: '',
    cep: '',
    logradouro: '',
    bairro: '',
    numero: '',
    complemento: '',
    cidade: '',
    estado: '',
    pais: '',
    latitude: 0,
    longitude: 0
  });
  const [cepError, setCepError] = useState<string | null>(null);
  const [lastCepFetched, setLastCepFetched] = useState<string>('');
  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);

  useEffect(() => {
    if (initialData) {
      setFormData({
        titulo: initialData.titulo || '',
        cep: initialData.cep || '',
        logradouro: initialData.logradouro || '',
        bairro: initialData.bairro || '',
        numero: initialData.numero || '',
        complemento: initialData.complemento || '',
        cidade: initialData.cidade || '',
        estado: initialData.estado || '',
        pais: initialData.pais || '',
        latitude: Number(initialData.latitude) || 0,
        longitude: Number(initialData.longitude) || 0
      });
    } else {
      setFormData({
        titulo: '',
        cep: '',
        logradouro: '',
        bairro: '',
        numero: '',
        complemento: '',
        cidade: '',
        estado: '',
        pais: '',
        latitude: 0,
        longitude: 0
      });
    }
  }, [initialData]);

  useEffect(() => {
    const digits = formData.cep.replace(/\D/g, '');
    if (digits.length === 8 && digits !== lastCepFetched) {
      const fetchData = async () => {
        try {
          const res = await fetch(
            `https://lernu-backend-dev.rede5.com.br/viacep/${digits}`
          );
          if (!res.ok) {
            throw new Error('CEP inválido');
          }
          const data = await res.json();
          setFormData(prev => ({
            ...prev,
            logradouro: data.logradouro || '',
            bairro: data.bairro || '',
            cidade: data.cidade || '',
            estado: data.estado || ''
          }));
          setLastCepFetched(digits);
          setCepError(null);
        } catch (err) {
          console.error('Erro ao buscar CEP:', err);
          setCepError('CEP não encontrado.');
        }
      };
      fetchData();
    }
  }, [formData.cep, lastCepFetched]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    const success = await onSubmit(formData);

    if (success) {
      setMessage({
        type: 'success',
        text: initialData ? '🔄 Endereço atualizado com sucesso!' : '🎉 Endereço cadastrado com sucesso!'
      });

      if (!initialData) {
        setFormData({
          titulo: '',
          cep: '',
          logradouro: '',
          bairro: '',
          numero: '',
          complemento: '',
          cidade: '',
          estado: '',
          pais: '',
          latitude: 0,
          longitude: 0
        });
      }

      setTimeout(() => setMessage(null), 3000);
    } else {
      setMessage({
        type: 'error',
        text: initialData ? 'Erro ao atualizar endereço' : 'Erro ao cadastrar endereço'
      });
    }
  };

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    let newValue = value;

    if (name === 'cep') {
      const digits = value.replace(/\D/g, '').slice(0, 8);
      newValue = digits.length > 5 ? `${digits.slice(0, 5)}-${digits.slice(5)}` : digits;
    }

    setFormData(prev => ({
      ...prev,
      [name]: name === 'latitude' || name === 'longitude' ? Number(newValue) : newValue
    }));

    if (message) setMessage(null);
  };

  const isValid =
    formData.titulo.trim() &&
    formData.cep.trim() &&
    formData.logradouro.trim() &&
    formData.bairro.trim() &&
    formData.numero.trim() &&
    formData.complemento.trim() &&
    formData.cidade.trim() &&
    formData.estado.trim() &&
    formData.pais.trim();

  return (
    <div className="bg-white rounded-lg shadow-md p-6">
      <div className="mb-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-2">
          {initialData ? '✏️ Editar Endereço' : ' Novo Endereço'}
        </h2>
        <p className="text-gray-600">
          {initialData ? 'Atualize os dados do endereço.' : 'Cadastre um novo endereço na plataforma SaveInMed.'}
        </p>
      </div>

      {message && (
        <div className={`mb-4 p-4 rounded-md ${
          message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'
        }`}>
          {message.text}
        </div>
      )}

      <form onSubmit={handleSubmit} className="space-y-6">
        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
          <div>
            <label htmlFor="titulo" className="block text-sm font-medium text-gray-700 mb-2">
              Título *
            </label>
            <input
              type="text"
              id="titulo"
              name="titulo"
              value={formData.titulo}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="Ex: Matriz"
            />
          </div>
          <div>
            <label htmlFor="cep" className="block text-sm font-medium text-gray-700 mb-2">
              CEP *
            </label>
            <input
              type="text"
              id="cep"
              name="cep"
              value={formData.cep}
              onChange={handleInputChange}
              required
              maxLength={9}
              pattern="\d{5}-\d{3}"
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="00000-000"
          />
          {cepError && (
            <p className="text-red-600 text-sm mt-1">{cepError}</p>
          )}
        </div>
        <div>
          <label htmlFor="logradouro" className="block text-sm font-medium text-gray-700 mb-2">
            Logradouro *
          </label>
          <input
            type="text"
            id="logradouro"
            name="logradouro"
            value={formData.logradouro}
            onChange={handleInputChange}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="Rua"
          />
        </div>
        <div>
          <label htmlFor="bairro" className="block text-sm font-medium text-gray-700 mb-2">
            Bairro *
          </label>
          <input
            type="text"
            id="bairro"
            name="bairro"
            value={formData.bairro}
            onChange={handleInputChange}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="Bairro"
          />
        </div>
        <div>
          <label htmlFor="numero" className="block text-sm font-medium text-gray-700 mb-2">
            Número *
          </label>
            <input
              type="text"
              id="numero"
              name="numero"
              value={formData.numero}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="123"
            />
          </div>
          <div>
            <label htmlFor="complemento" className="block text-sm font-medium text-gray-700 mb-2">
              Complemento *
            </label>
            <input
              type="text"
              id="complemento"
              name="complemento"
              value={formData.complemento}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="Apto, sala, etc"
            />
          </div>
          <div>
            <label htmlFor="cidade" className="block text-sm font-medium text-gray-700 mb-2">
              Cidade *
            </label>
            <input
              type="text"
              id="cidade"
              name="cidade"
              value={formData.cidade}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="Cidade"
            />
          </div>
          <div>
            <label htmlFor="estado" className="block text-sm font-medium text-gray-700 mb-2">
              Estado *
            </label>
            <input
              type="text"
              id="estado"
              name="estado"
              value={formData.estado}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="Estado"
            />
          </div>
          <div>
            <label htmlFor="pais" className="block text-sm font-medium text-gray-700 mb-2">
              País *
            </label>
            <input
              type="text"
              id="pais"
              name="pais"
              value={formData.pais}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="Brasil"
            />
          </div>
          <div>
            <label htmlFor="latitude" className="block text-sm font-medium text-gray-700 mb-2">
              Latitude *
            </label>
            <input
              type="number"
              id="latitude"
              name="latitude"
              step="any"
              value={formData.latitude}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            />
          </div>
          <div>
            <label htmlFor="longitude" className="block text-sm font-medium text-gray-700 mb-2">
              Longitude *
            </label>
            <input
              type="number"
              id="longitude"
              name="longitude"
              step="any"
              value={formData.longitude}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            />
          </div>
        </div>

        <div className="flex gap-4">
          <button
            type="submit"
            disabled={loading || !isValid}
            className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
          >
            {loading ? '⏳ Processando...' : (initialData ? '🔄 Atualizar' : ' Cadastrar')}
          </button>

          {onCancel && (
            <button
              type="button"
              onClick={onCancel}
              disabled={loading}
              className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
            >
               Cancelar
            </button>
          )}
        </div>
      </form>
    </div>
  );
};

export default EnderecoForm;


src/components/EnderecoList.tsx

import React from 'react';
import { Models } from 'appwrite';
import SearchBar from './SearchBar';
import RefreshButton from './RefreshButton';
import ListHeader from './ListHeader';
import DataTable, { Column } from './DataTable';
import Pagination from './Pagination';
import ActionButton from './ActionButton';

interface EnderecoListProps {
  enderecos: Models.Document[];
  loading: boolean;
  error: string | null;
  totalEnderecos: number;
  currentPage: number;
  pageSize: number;
  onEdit: (endereco: Models.Document) => void;
  onDelete: (id: string) => Promise<boolean>;
  onRefresh: () => void;
  onPrevPage: () => void;
  onNextPage: () => void;
  onSearch: (termo: string) => void;
}

const EnderecoList: React.FC<EnderecoListProps> = ({
  enderecos,
  loading,
  error,
  totalEnderecos,
  currentPage,
  pageSize,
  onEdit,
  onDelete,
  onRefresh,
  onPrevPage,
  onNextPage,
  onSearch
}) => {
  const totalPages = Math.ceil(totalEnderecos / pageSize);
  const startItem = (currentPage - 1) * pageSize + 1;
  const endItem = Math.min(currentPage * pageSize, totalEnderecos);

  const [search, setSearch] = React.useState('');

  const handleSearch = () => {
    onSearch(search);
  };

  const handleDelete = async (id: string) => {
    if (confirm('Tem certeza que deseja deletar este endereço?')) {
      await onDelete(id);
    }
  };

  const columns: Column<Models.Document>[] = [
    { key: 'titulo', header: 'Título' },
    { key: 'cep', header: 'CEP' },
    { key: 'cidade', header: 'Cidade' },
    { key: 'estado', header: 'Estado' },
    { key: 'pais', header: 'País' },
  ];

  return (
    <div className="container mx-auto px-4 py-8">
      <ListHeader title="Lista de Endereços">
        <SearchBar
          value={search}
          onChange={setSearch}
          onSearch={handleSearch}
          placeholder="Buscar título, CEP ou cidade"
        />
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
          {error}
        </div>
      )}

      {loading ? (
        <div className="flex justify-center items-center min-h-screen">
          <div className="text-lg">Carregando endereços...</div>
        </div>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={enderecos}
            actions={(end) => (
              <>
                <ActionButton
                  variant="edit"
                  onClick={() => onEdit(end)}
                >
                  ✏️ Editar
                </ActionButton>
                <ActionButton
                  variant="delete"
                  onClick={() => handleDelete(end.$id)}
                >
                  🗑️ Deletar
                </ActionButton>
              </>
            )}
          />

          <div className="mt-4 flex justify-between items-center">
            <div className="text-sm text-gray-600">
              {totalEnderecos > 0 ? (
                <>Mostrando {startItem} - {endItem} de {totalEnderecos} endereços</>
              ) : (
                'Total de endereços: 0'
              )}
            </div>

            <Pagination
              page={currentPage}
              total={totalPages}
              onPrev={onPrevPage}
              onNext={onNextPage}
            />
          </div>
        </>
      )}
    </div>
  );
};

export default EnderecoList;


src/components/FaturaForm.tsx

import React, { useState, useEffect } from 'react';
import { Models } from 'appwrite';
import { FaturaFormData } from '@/hooks/useFaturas';

interface FaturaFormProps {
  onSubmit: (data: FaturaFormData) => Promise<boolean>;
  onCancel?: () => void;
  initialData?: Models.Document | null;
  loading?: boolean;
}

const FaturaForm: React.FC<FaturaFormProps> = ({
  onSubmit,
  onCancel,
  initialData,
  loading = false,
}) => {
  const [formData, setFormData] = useState<FaturaFormData>({ nome: '' });
  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);

  useEffect(() => {
    if (initialData) {
      setFormData({ nome: initialData.nome });
    } else {
      setFormData({ nome: '' });
    }
  }, [initialData]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const success = await onSubmit(formData);
    if (success) {
      setMessage({
        type: 'success',
        text: initialData ? '🔄 Fatura atualizada com sucesso!' : '🎉 Fatura cadastrada com sucesso!'
      });
      if (!initialData) {
        setFormData({ nome: '' });
      }
      setTimeout(() => setMessage(null), 3000);
    } else {
      setMessage({ type: 'error', text: initialData ? 'Erro ao atualizar fatura' : 'Erro ao cadastrar fatura' });
    }
  };

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
    if (message) setMessage(null);
  };

  return (
    <div className="bg-white rounded-lg shadow-md p-6">
      <div className="mb-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-2">
          {initialData ? '✏️ Editar Fatura' : ' Nova Fatura'}
        </h2>
        <p className="text-gray-600">
          {initialData ? 'Atualize os dados da fatura.' : 'Cadastre uma nova fatura na plataforma SaveInMed.'}
        </p>
      </div>

      {message && (
        <div className={`mb-4 p-4 rounded-md ${message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'}`}>
          {message.text}
        </div>
      )}

      <form onSubmit={handleSubmit} className="space-y-6">
        <div>
          <label htmlFor="nome" className="block text-sm font-medium text-gray-700 mb-2">
            Nome da Fatura *
          </label>
          <input
            type="text"
            id="nome"
            name="nome"
            value={formData.nome}
            onChange={handleChange}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="Ex: Fatura de Janeiro"
          />
        </div>
        <div className="flex gap-4">
          <button
            type="submit"
            disabled={loading}
            className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
          >
            {loading ? '⏳ Processando...' : initialData ? '🔄 Atualizar' : ' Cadastrar'}
          </button>
          {onCancel && (
            <button
              type="button"
              onClick={onCancel}
              disabled={loading}
              className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
            >
               Cancelar
            </button>
          )}
        </div>
      </form>
    </div>
  );
};

export default FaturaForm;


src/components/FaturaList.tsx

import React from 'react';
import { Models } from 'appwrite';
import SearchBar from './SearchBar';
import RefreshButton from './RefreshButton';
import ListHeader from './ListHeader';
import DataTable, { Column } from './DataTable';
import Pagination from './Pagination';
import ActionButton from './ActionButton';

interface FaturaListProps {
  faturas: Models.Document[];
  loading: boolean;
  error: string | null;
  totalFaturas: number;
  currentPage: number;
  pageSize: number;
  onEdit: (fatura: Models.Document) => void;
  onDelete: (id: string) => Promise<boolean>;
  onRefresh: () => void;
  onPrevPage: () => void;
  onNextPage: () => void;
  onSearch: (nome: string) => void;
}

const FaturaList: React.FC<FaturaListProps> = ({
  faturas,
  loading,
  error,
  totalFaturas,
  currentPage,
  pageSize,
  onEdit,
  onDelete,
  onRefresh,
  onPrevPage,
  onNextPage,
  onSearch
}) => {
  const totalPages = Math.ceil(totalFaturas / pageSize);
  const startItem = (currentPage - 1) * pageSize + 1;
  const endItem = Math.min(currentPage * pageSize, totalFaturas);

  const [search, setSearch] = React.useState('');

  const handleSearch = () => {
    onSearch(search);
  };

  const handleDelete = async (id: string) => {
    if (confirm('Tem certeza que deseja deletar esta fatura?')) {
      await onDelete(id);
    }
  };

  const columns: Column<Models.Document>[] = [
    { key: 'nome', header: 'Nome' },
    { key: '$id', header: 'ID' },
    { key: '$createdAt', header: 'Data de Criação', render: row => new Date(row.$createdAt).toLocaleDateString('pt-BR') },
  ];

  return (
    <div className="container mx-auto px-4 py-8">
      <ListHeader title="Lista de Faturas">
        <SearchBar
          value={search}
          onChange={setSearch}
          onSearch={handleSearch}
          placeholder="Buscar fatura"
        />
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
          {error}
        </div>
      )}

      {loading ? (
        <div className="flex justify-center items-center min-h-screen">
          <div className="text-lg">Carregando faturas...</div>
        </div>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={faturas}
            actions={(fatura) => (
              <>
                <ActionButton
                  variant="edit"
                  onClick={() => onEdit(fatura)}
                >
                  ✏️ Editar
                </ActionButton>
                <ActionButton
                  variant="delete"
                  onClick={() => handleDelete(fatura.$id)}
                >
                  🗑️ Deletar
                </ActionButton>
              </>
            )}
          />

          <div className="mt-4 flex justify-between items-center">
            <div className="text-sm text-gray-600">
              {totalFaturas > 0 ? (
                <>Mostrando {startItem} - {endItem} de {totalFaturas} faturas</>
              ) : (
                'Total de faturas: 0'
              )}
            </div>

            <Pagination
              page={currentPage}
              total={totalPages}
              onPrev={onPrevPage}
              onNext={onNextPage}
            />
          </div>
        </>
      )}
    </div>
  );
};

export default FaturaList;


src/components/Header.tsx

'use client';
import { useState, useEffect, useRef } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Navbar from './Navbar';

interface HeaderProps {
  user: Models.User<Models.Preferences> | null;
  title?: string;
  subtitle?: string;
  showBackButton?: boolean;
}

const Header = ({ user, title = 'SaveInMed', subtitle = 'Plataforma B2B de Medicamentos', showBackButton = false }: HeaderProps) => {
  const router = useRouter();
  const [isOpen, setIsOpen] = useState(false);
  const dropdownRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
        setIsOpen(false);
      }
    };
    document.addEventListener('mousedown', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, []);

  const handleLogout = async () => {
    try {
      await account.deleteSession('current');
      router.push('/');
    } catch (error) {
      console.error('Erro no logout:', error);
    }
  };

  return (
    <>
      <header className="bg-white shadow-sm border-b">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <div className="flex justify-between items-center h-16">
            {/* Logo e navegação */}
            <div className="flex items-center space-x-4">
              {showBackButton && (
                <button 
                  onClick={() => router.push('/dashboard')}
                  className="text-gray-600 hover:text-gray-900 transition-colors cursor-pointer"
                >
                  <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
                  </svg>
                </button>
              )}
              <div className="w-10 h-10 bg-gradient-to-r from-blue-600 to-green-600 rounded-lg flex items-center justify-center">
                <svg className="w-6 h-6 text-white" fill="currentColor" viewBox="0 0 20 20">
                  <path d="M3 4a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H4a1 1 0 01-1-1V4zM3 10a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H4a1 1 0 01-1-1v-6zM14 9a1 1 0 00-1 1v6a1 1 0 001 1h2a1 1 0 001-1v-6a1 1 0 00-1-1h-2z" />
                </svg>
              </div>
              <div>
                <h1 className="text-2xl font-bold bg-gradient-to-r from-blue-600 to-green-600 bg-clip-text text-transparent">
                  {title}
                </h1>
                <p className="text-xs text-gray-500">{subtitle}</p>
              </div>
            </div>
            
            {/* Navbar Central */}
            <div className="flex-1 flex justify-center mx-8">
              <Navbar />
            </div>
            
            {/* Informações do usuário - SEM EMAIL no header */}
            <div className="flex items-center space-x-4">
              <div className="relative" ref={dropdownRef}>
                <button
                  onClick={() => setIsOpen(!isOpen)}
                  className="flex items-center space-x-3 hover:bg-gray-50 rounded-lg p-2 transition-colors cursor-pointer"
                >
                  <div className="w-8 h-8 bg-gradient-to-r from-blue-500 to-green-500 rounded-full flex items-center justify-center">
                    <span className="text-white text-sm font-semibold">
                      {user?.name?.charAt(0).toUpperCase()}
                    </span>
                  </div>
                  <div className="hidden md:block">
                    <p className="text-sm font-medium text-gray-900">{user?.name}</p>
                  </div>
                  <svg className="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
                  </svg>
                </button>
                {isOpen && (
                  <ul className="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg z-10">
                    <li>
                      <Link href="/perfil" className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-t-lg">
                        Ver Perfil
                      </Link>
                    </li>
                    <li>
                      <button
                        onClick={handleLogout}
                        className="w-full text-left block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-b-lg cursor-pointer"
                      >
                        Sair
                      </button>
                    </li>
                  </ul>
                )}
              </div>
            </div>
          </div>
        </div>
      </header>
      
      {/* Espaçamento após header */}
      <div className="h-4"></div>
    </>
  );
};

export default Header;

src/components/LaboratorioForm.tsx

import React, { useState, useEffect } from 'react';
import { Models } from 'appwrite';
import { LaboratorioFormData } from '@/hooks/useLaboratorios';

interface LaboratorioFormProps {
  onSubmit: (data: LaboratorioFormData) => Promise<boolean>;
  onCancel?: () => void;
  initialData?: Models.Document | null;
  loading?: boolean;
}

const LaboratorioForm: React.FC<LaboratorioFormProps> = ({
  onSubmit,
  onCancel,
  initialData,
  loading = false
}) => {
  const [formData, setFormData] = useState<LaboratorioFormData>({
    nome: ''
  });
  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);

  useEffect(() => {
    if (initialData) {
      setFormData({ nome: initialData.nome || '' });
    } else {
      setFormData({ nome: '' });
    }
  }, [initialData]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    const success = await onSubmit(formData);
    
    if (success) {
      setMessage({ 
        type: 'success', 
        text: initialData ? '🔄 Laboratório atualizado com sucesso!' : '🎉 Laboratório cadastrado com sucesso!' 
      });
      
      if (!initialData) {
        setFormData({ nome: '' });
      }
      
      setTimeout(() => setMessage(null), 3000);
    } else {
      setMessage({ 
        type: 'error', 
        text: initialData ? 'Erro ao atualizar laboratório' : 'Erro ao cadastrar laboratório' 
      });
    }
  };

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
    if (message) setMessage(null);
  };

  return (
    <div className="bg-white rounded-lg shadow-md p-6">
      <div className="mb-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-2">
          {initialData ? '✏️ Editar Laboratório' : ' Novo Laboratório'}
        </h2>
        <p className="text-gray-600">
          {initialData ? 'Atualize os dados do laboratório.' : 'Cadastre um novo laboratório na plataforma SaveInMed.'}
        </p>
      </div>

      {message && (
        <div className={`mb-4 p-4 rounded-md ${
          message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'
        }`}>
          {message.text}
        </div>
      )}

      <form onSubmit={handleSubmit} className="space-y-6">
        <div>
          <label htmlFor="nome" className="block text-sm font-medium text-gray-700 mb-2">
            Nome do Laboratório *
          </label>
          <input
            type="text"
            id="nome"
            name="nome"
            value={formData.nome}
            onChange={handleInputChange}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed text-gray-900 bg-white"
            placeholder="Digite o nome do laboratório"
          />
        </div>

        <div className="flex gap-4">
          <button
            type="submit"
            disabled={loading || !formData.nome.trim()}
            className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
          >
            {loading ? '⏳ Processando...' : (initialData ? '🔄 Atualizar' : ' Cadastrar')}
          </button>
          
          {onCancel && (
            <button
              type="button"
              onClick={onCancel}
              disabled={loading}
              className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
            >
               Cancelar
            </button>
          )}
        </div>
      </form>
    </div>
  );
};

export default LaboratorioForm;

src/components/LaboratorioList.tsx

import React from 'react';
import { Models } from 'appwrite';
import SearchBar from './SearchBar';
import RefreshButton from './RefreshButton';
import ListHeader from './ListHeader';
import DataTable, { Column } from './DataTable';
import Pagination from './Pagination';
import ActionButton from './ActionButton';

interface LaboratorioListProps {
  laboratorios: Models.Document[];
  loading: boolean;
  error: string | null;
  totalLaboratorios: number;
  currentPage: number;
  pageSize: number;
  onEdit: (lab: Models.Document) => void;
  onDelete: (id: string) => Promise<boolean>;
  onRefresh: () => void;
  onPrevPage: () => void;
  onNextPage: () => void;
  onSearch: (nome: string) => void;
}

const LaboratorioList: React.FC<LaboratorioListProps> = ({
  laboratorios,
  loading,
  error,
  totalLaboratorios,
  currentPage,
  pageSize,
  onEdit,
  onDelete,
  onRefresh,
  onPrevPage,
  onNextPage,
  onSearch
}) => {
  const totalPages = Math.ceil(totalLaboratorios / pageSize);
  const startItem = (currentPage - 1) * pageSize + 1;
  const endItem = Math.min(currentPage * pageSize, totalLaboratorios);

  const [search, setSearch] = React.useState('');

  const handleSearch = () => {
    onSearch(search);
  };

  const handleDelete = async (id: string) => {
    if (confirm('Tem certeza que deseja deletar este laboratório?')) {
      await onDelete(id);
    }
  };

  const columns: Column<Models.Document>[] = [
    { key: 'nome', header: 'Nome' },
    { key: '$id', header: 'ID' },
    { key: '$createdAt', header: 'Data de Criação', render: row => new Date(row.$createdAt).toLocaleDateString('pt-BR') },
  ];

  return (
    <div className="container mx-auto px-4 py-8">
      <ListHeader title="Lista de Laboratórios">
        <SearchBar
          value={search}
          onChange={setSearch}
          onSearch={handleSearch}
          placeholder="Buscar laboratório"
        />
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
          {error}
        </div>
      )}

      {loading ? (
        <div className="flex justify-center items-center min-h-screen">
          <div className="text-lg">Carregando laboratórios...</div>
        </div>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={laboratorios}
            actions={(lab) => (
              <>
                <ActionButton
                  variant="edit"
                  onClick={() => onEdit(lab)}
                >
                  ✏️ Editar
                </ActionButton>
                <ActionButton
                  variant="delete"
                  onClick={() => handleDelete(lab.$id)}
                >
                  🗑️ Deletar
                </ActionButton>
              </>
            )}
          />

          <div className="mt-4 flex justify-between items-center">
            <div className="text-sm text-gray-600">
              {totalLaboratorios > 0 ? (
                <>Mostrando {startItem} - {endItem} de {totalLaboratorios} laboratórios</>
              ) : (
                'Total de laboratórios: 0'
              )}
            </div>

            <Pagination
              page={currentPage}
              total={totalPages}
              onPrev={onPrevPage}
              onNext={onNextPage}
            />
          </div>
        </>
      )}
    </div>
  );
};

export default LaboratorioList;

src/components/ListHeader.tsx

import React from 'react';

type Props = {
  title: string;
  children?: React.ReactNode;
};

const ListHeader: React.FC<Props> = ({ title, children }) => (
  <div className="flex justify-between items-center mb-6">
    <h1 className="text-gray-800 font-bold text-2xl">{title}</h1>
    <div className="flex items-center gap-2">{children}</div>
  </div>
);

export default ListHeader;


src/components/Navbar.tsx

import { useState, useRef, useEffect } from 'react';
import Link from 'next/link';

interface NavItem {
  label: string;
  href: string;
}

interface NavCategory {
  label: string;
  icon: string;
  items: NavItem[];
}

const Navbar = () => {
  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
  const [activeDropdown, setActiveDropdown] = useState<string | null>(null);
  const timeoutRef = useRef<NodeJS.Timeout | null>(null);

  const categories: NavCategory[] = [
    {
      label: 'Loja Virtual',
      icon: '🛍️',
      items: [
        { label: 'Catálogo de Produtos', href: '/catalogo-produtos' },
        { label: 'Produtos', href: '/produtos' },
        { label: 'Categorias', href: '/categorias' },
        { label: 'Carrinhos', href: '/carrinhos' },
        { label: 'Pedidos', href: '/pedidos' },
        { label: 'Faturas', href: '/faturas' },
        { label: 'Pagamentos', href: '/pagamentos' },
        { label: 'Laboratórios', href: '/laboratorios' },
        { label: 'Usuários', href: '/usuarios' },
        { label: 'Endereços', href: '/enderecos' },
        { label: 'Empresas', href: '/dashboard/empresa-novo' },
      ],
    },
    {
      label: 'Comunicação',
      icon: '💬',
      items: [
        { label: 'Mensagens', href: '/mensagens' },
      ],
    },
    {
      label: 'Utilitários',
      icon: '🛠️',
      items: [
        { label: 'Função Caju', href: '/caju' },
      ],
    },
  ];

  const handleMouseEnter = (categoryLabel: string) => {
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }
    setActiveDropdown(categoryLabel);
  };

  const handleMouseLeave = () => {
    timeoutRef.current = setTimeout(() => {
      setActiveDropdown(null);
    }, 150); // 150ms delay antes de fechar
  };

  useEffect(() => {
    return () => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
    };
  }, []);

  return (
    <nav className="bg-transparent">
      <div className="px-4">
        <div className="flex justify-center items-center h-12">
          {/* Desktop Navigation */}
          <div className="hidden md:flex items-center space-x-6">
            {categories.map((category) => (
              <div
                key={category.label}
                className="relative"
                onMouseEnter={() => handleMouseEnter(category.label)}
                onMouseLeave={handleMouseLeave}
              >
                <button
                  className="flex items-center space-x-1 text-gray-700 hover:text-blue-600 px-3 py-2 rounded-md text-sm font-medium transition-colors cursor-pointer"
                  role="button"
                  aria-haspopup="true"
                  aria-expanded={activeDropdown === category.label}
                >
                  <span>{category.icon}</span>
                  <span>{category.label}</span>
                  <svg className="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
                  </svg>
                </button>

                {/* Dropdown Menu */}
                {activeDropdown === category.label && (
                  <div
                    className="absolute top-full left-0 mt-1 w-56 bg-white rounded-md shadow-lg border border-gray-200 z-50"
                    onMouseEnter={() => handleMouseEnter(category.label)}
                    onMouseLeave={handleMouseLeave}
                  >
                    <div className="py-1">
                      {category.items.map((item) => (
                        <Link
                          key={item.href}
                          href={item.href}
                          className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 hover:text-blue-600 transition-colors cursor-pointer"
                        >
                          {item.label}
                        </Link>
                      ))}
                    </div>
                  </div>
                )}
              </div>
            ))}
          </div>

          {/* Mobile menu button */}
          <div className="md:hidden">
            <button
              onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
              className="text-gray-700 hover:text-blue-600 p-2 rounded-md transition-colors cursor-pointer"
            >
              <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                {isMobileMenuOpen ? (
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
                ) : (
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
                )}
              </svg>
            </button>
          </div>
        </div>

        {/* Mobile Navigation */}
        {isMobileMenuOpen && (
          <div className="md:hidden border-t border-gray-200 bg-white rounded-b-lg shadow-lg">
            <div className="py-2 space-y-1">
              {categories.map((category) => (
                <div key={category.label}>
                  <button
                    onClick={() =>
                      setActiveDropdown(
                        activeDropdown === category.label ? null : category.label
                      )
                    }
                    className="w-full flex items-center justify-between px-3 py-2 text-gray-700 hover:bg-gray-50 hover:text-blue-600 transition-colors cursor-pointer"
                    role="button"
                    aria-haspopup="true"
                    aria-expanded={activeDropdown === category.label}
                  >
                    <div className="flex items-center space-x-2">
                      <span>{category.icon}</span>
                      <span className="font-medium">{category.label}</span>
                    </div>
                    <svg
                      className={`w-4 h-4 transition-transform ${
                        activeDropdown === category.label ? 'rotate-180' : ''
                      }`}
                      fill="none"
                      stroke="currentColor"
                      viewBox="0 0 24 24"
                    >
                      <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
                    </svg>
                  </button>

                  {/* Mobile Dropdown */}
                  {activeDropdown === category.label && (
                    <div className="bg-gray-50">
                      {category.items.map((item) => (
                        <Link
                          key={item.href}
                          href={item.href}
                          className="block px-8 py-2 text-sm text-gray-600 hover:text-blue-600 transition-colors cursor-pointer"
                          onClick={() => setIsMobileMenuOpen(false)}
                        >
                          {item.label}
                        </Link>
                      ))}
                    </div>
                  )}
                </div>
              ))}
            </div>
          </div>
        )}
      </div>
    </nav>
  );
};

export default Navbar;

src/components/PagamentoForm.tsx

import React, { useState, useEffect } from 'react';
import { Models } from 'appwrite';
import { PagamentoData } from '@/services/pagamentoService';

interface PagamentoFormProps {
  onSubmit: (data: PagamentoData) => Promise<boolean>;
  onCancel?: () => void;
  initialData?: Models.Document | null;
  loading?: boolean;
}

const statusOptions = ['pendente', 'pago', 'cancelado'];
const metodoOptions = ['pix', 'boleto', 'cartao'];

const PagamentoForm: React.FC<PagamentoFormProps> = ({
  onSubmit,
  onCancel,
  initialData,
  loading = false
}) => {
  const [formData, setFormData] = useState<PagamentoData>({
    pedidos: '',
    status: 'pendente',
    metodo: 'pix',
    valor: 0
  });
  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);

  useEffect(() => {
    if (initialData) {
      setFormData({
        pedidos: initialData.pedidos || '',
        status: initialData.status || 'pendente',
        metodo: initialData.metodo || 'pix',
        valor: Number(initialData.valor) || 0
      });
    } else {
      setFormData({ pedidos: '', status: 'pendente', metodo: 'pix', valor: 0 });
    }
  }, [initialData]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    const success = await onSubmit(formData);

    if (success) {
      setMessage({
        type: 'success',
        text: initialData ? '🔄 Pagamento atualizado com sucesso!' : '🎉 Pagamento cadastrado com sucesso!'
      });

      if (!initialData) {
        setFormData({ pedidos: '', status: 'pendente', metodo: 'pix', valor: 0 });
      }

      setTimeout(() => setMessage(null), 3000);
    } else {
      setMessage({
        type: 'error',
        text: initialData ? 'Erro ao atualizar pagamento' : 'Erro ao cadastrar pagamento'
      });
    }
  };

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: name === 'valor' ? Number(value) : value }));
    if (message) setMessage(null);
  };

  return (
    <div className="bg-white rounded-lg shadow-md p-6">
      <div className="mb-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-2">
          {initialData ? '✏️ Editar Pagamento' : ' Novo Pagamento'}
        </h2>
        <p className="text-gray-600">
          {initialData ? 'Atualize os dados do pagamento.' : 'Cadastre um novo pagamento.'}
        </p>
      </div>

      {message && (
        <div className={`mb-4 p-4 rounded-md ${
          message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'
        }`}>
          {message.text}
        </div>
      )}

      <form onSubmit={handleSubmit} className="space-y-6">
        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
          <div>
            <label htmlFor="pedidos" className="block text-sm font-medium text-gray-700 mb-2">
              Pedido ID *
            </label>
            <input
              type="text"
              id="pedidos"
              name="pedidos"
              value={formData.pedidos}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="ID do pedido"
            />
          </div>

          <div>
            <label htmlFor="status" className="block text-sm font-medium text-gray-700 mb-2">
              Status *
            </label>
            <select
              id="status"
              name="status"
              value={formData.status}
              onChange={handleInputChange}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              disabled={loading}
            >
              {statusOptions.map(option => (
                <option key={option} value={option}>{option}</option>
              ))}
            </select>
          </div>

          <div>
            <label htmlFor="metodo" className="block text-sm font-medium text-gray-700 mb-2">
              Método *
            </label>
            <select
              id="metodo"
              name="metodo"
              value={formData.metodo}
              onChange={handleInputChange}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              disabled={loading}
            >
              {metodoOptions.map(option => (
                <option key={option} value={option}>{option}</option>
              ))}
            </select>
          </div>

          <div>
            <label htmlFor="valor" className="block text-sm font-medium text-gray-700 mb-2">
              Valor (R$) *
            </label>
            <input
              type="number"
              step="0.01"
              id="valor"
              name="valor"
              value={formData.valor}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="0,00"
            />
          </div>
        </div>

        <div className="flex gap-4">
          <button
            type="submit"
            disabled={loading}
            className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
          >
            {loading ? '⏳ Processando...' : (initialData ? '🔄 Atualizar' : ' Cadastrar')}
          </button>

          {onCancel && (
            <button
              type="button"
              onClick={onCancel}
              disabled={loading}
              className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
            >
               Cancelar
            </button>
          )}
        </div>
      </form>
    </div>
  );
};

export default PagamentoForm;


src/components/PagamentoList.tsx

import React from 'react';
import { Models } from 'appwrite';
import RefreshButton from './RefreshButton';
import ListHeader from './ListHeader';
import DataTable, { Column } from './DataTable';
import Pagination from './Pagination';
import ActionButton from './ActionButton';
import SearchBar from './SearchBar';

interface PagamentoListProps {
  pagamentos: Models.Document[];
  loading: boolean;
  error: string | null;
  totalPagamentos: number;
  currentPage: number;
  pageSize: number;
  onEdit: (p: Models.Document) => void;
  onDelete: (id: string) => Promise<boolean>;
  onRefresh: () => void;
  onPrevPage: () => void;
  onNextPage: () => void;
  onSearch: (term: string) => void;
}

const PagamentoList: React.FC<PagamentoListProps> = ({
  pagamentos,
  loading,
  error,
  totalPagamentos,
  currentPage,
  pageSize,
  onEdit,
  onDelete,
  onRefresh,
  onPrevPage,
  onNextPage,
  onSearch,
}) => {
  const totalPages = Math.ceil(totalPagamentos / pageSize);
  const startItem = (currentPage - 1) * pageSize + 1;
  const endItem = Math.min(currentPage * pageSize, totalPagamentos);
  const [search, setSearch] = React.useState('');

  const columns: Column<Models.Document>[] = [
    { key: 'pedidos', header: 'Pedido' },
    { key: 'status', header: 'Status' },
    { key: 'metodo', header: 'Método' },
    { key: 'valor', header: 'Valor', render: row =>
        Number(row.valor).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }) },
    { key: '$id', header: 'ID' },
    { key: '$createdAt', header: 'Data de Criação', render: row =>
        new Date(row.$createdAt).toLocaleDateString('pt-BR') },
  ];

  const handleDelete = async (id: string) => {
    if (confirm('Tem certeza que deseja deletar este pagamento?')) {
      await onDelete(id);
    }
  };

  return (
    <div className="container mx-auto px-4 py-8">
      <ListHeader title="Lista de Pagamentos">
        <SearchBar
          value={search}
          onChange={setSearch}
          onSearch={() => onSearch(search)}
          placeholder="Buscar status"
        />
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
          {error}
        </div>
      )}

      {loading ? (
        <div className="flex justify-center items-center min-h-screen">
          <div className="text-lg">Carregando pagamentos...</div>
        </div>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={pagamentos}
            actions={(pag) => (
              <>
                <ActionButton variant="edit" onClick={() => onEdit(pag)}>
                  ✏️ Editar
                </ActionButton>
                <ActionButton variant="delete" onClick={() => handleDelete(pag.$id)}>
                  🗑️ Deletar
                </ActionButton>
              </>
            )}
          />

          <div className="mt-4 flex justify-between items-center">
            <div className="text-sm text-gray-600">
              {totalPagamentos > 0 ? (
                <>Mostrando {startItem} - {endItem} de {totalPagamentos} pagamentos</>
              ) : (
                'Total de pagamentos: 0'
              )}
            </div>

            <Pagination
              page={currentPage}
              total={totalPages}
              onPrev={onPrevPage}
              onNext={onNextPage}
            />
          </div>
        </>
      )}
    </div>
  );
};

export default PagamentoList;


src/components/Pagination.tsx

import React from 'react';

type Props = {
  page: number;
  total: number;
  onPrev: () => void;
  onNext: () => void;
};

const Pagination: React.FC<Props> = ({ page, total, onPrev, onNext }) => {
  if (total <= 1) return null;
  
  return (
    <div className="flex gap-2 items-center">
      <button
        onClick={onPrev}
        disabled={page <= 1}
        className="
          px-3 py-1 text-sm border border-gray-300 rounded-md
          bg-white text-gray-700 hover:bg-gray-50
          transition-colors duration-200
          disabled:opacity-50 disabled:cursor-not-allowed
          disabled:hover:bg-white
          cursor-pointer
        "
      >
        Anterior
      </button>
      <span className="px-3 py-1 text-gray-700 font-medium">
        {page} / {total}
      </span>
      <button
        onClick={onNext}
        disabled={page >= total}
        className="
          px-3 py-1 text-sm border border-gray-300 rounded-md
          bg-white text-gray-700 hover:bg-gray-50
          transition-colors duration-200
          disabled:opacity-50 disabled:cursor-not-allowed
          disabled:hover:bg-white
          cursor-pointer
        "
      >
        Próxima
      </button>
    </div>
  );
};

export default Pagination;


src/components/PedidoForm.tsx

import React, { useState, useEffect } from 'react';
import { Models } from 'appwrite';
import { PedidoData } from '@/services/pedidoService';
import { usuarioService } from '@/services/usuarioService';
import { empresaService } from '@/services/empresaService';

interface PedidoFormProps {
  onSubmit: (data: PedidoData) => Promise<boolean>;
  onCancel?: () => void;
  initialData?: Models.Document | null;
  loading?: boolean;
  statusOptions: string[];
}

const PedidoForm: React.FC<PedidoFormProps> = ({
  onSubmit,
  onCancel,
  initialData,
  loading = false,
type Props = {
  onSubmit: (data: ProdutoData) => Promise<void>;
};
const ProdutoForm: React.FC<Props> = ({
  const handleSubmit = (e: React.FormEvent) => {
    onSubmit(formData);
  const handleInputChange = (field: keyof ProdutoData, value: string | number) => {
    setFormData(prev => ({ ...prev, [field]: value }));
      <h2 className="text-2xl font-bold text-gray-900 mb-2">
        {initialData ? 'Editar Produto' : 'Novo Produto'}
      </h2>
      <p className="text-gray-600 mb-6">
        {initialData ? 'Atualize os dados do produto.' : 'Preencha as informações para cadastrar um novo produto.'}
      </p>
            Nome do Produto
            type="text"
            onChange={(e) => handleInputChange('nome', e.target.value)}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"

        <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
          <div>
            <label htmlFor="preco-original" className="block text-sm font-medium text-gray-700 mb-2">
              Preço Original
            </label>
            <input
              id="preco-original"
              type="number"
              value={formData['preco-original']}
              onChange={(e) => handleInputChange('preco-original', parseFloat(e.target.value) || 0)}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"
              step="0.01"
              min="0"
              disabled={loading}
              required
            />
          </div>
          <div>
            <label htmlFor="preco-atual" className="block text-sm font-medium text-gray-700 mb-2">
              Preço Atual
            </label>
            <input
              id="preco-atual"
              type="number"
              value={formData['preco-atual']}
              onChange={(e) => handleInputChange('preco-atual', parseFloat(e.target.value) || 0)}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"
              step="0.01"
              min="0"
              disabled={loading}
              required
            />
          </div>

            ID do Catálogo de Produto
            type="text"
            onChange={(e) => handleInputChange('catalogo-produto-id', e.target.value)}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"
            required

            ID da Empresa
            type="text"
            onChange={(e) => handleInputChange('empresa-id', e.target.value)}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"
            required

            className="flex-1 bg-blue-600 text-white h-10 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500"
            {loading ? 'Salvando...' : 'Salvar'}
              className="flex-1 bg-gray-600 text-white h-10 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500"
              Cancelar
```tsx
import React from 'react';
import { Models } from 'appwrite';
import SearchBar from '@/components/SearchBar';
import RefreshButton from '@/components/RefreshButton';
import ListHeader from '@/components/ListHeader';
import DataTable, { Column } from '@/components/DataTable';
import Pagination from '@/components/Pagination';
import ActionButton from './ActionButton';

type Props = {
  page: number;
  total: number;
  onEdit: (doc: Models.Document) => void;
  onDelete: (id: string) => void;
  onPrev: () => void;
  onNext: () => void;
  onSearch: (term: string) => void;
};
const columns: Column<Models.Document>[] = [
  {
    key: 'catalogo-produtos.descricao',
    header: 'Produto',
    render: produto => produto['catalogo-produtos']?.descricao || 'N/A'
  },
  {
    key: 'preco-atual',
    header: 'Preço Atual',
    render: produto => `R$ ${produto['preco-atual']?.toFixed(2) || '0,00'}`
  },
  {
    key: 'empresas.nome-fantasia',
    header: 'Empresa',
    render: produto => produto.empresas?.['nome-fantasia'] || 'N/A'
  },
  {
    key: 'catalogo-produtos.categorias.nome',
    header: 'Categoria',
    render: produto => produto['catalogo-produtos']?.categorias?.nome || 'N/A'
  }
];

const ProdutoList: React.FC<Props> = ({
  page,
  total,
  onPrev,
  onNext,
  onSearch,
    <div className="space-y-2">
      <ListHeader title="Produtos">
          onSearch={() => onSearch(search)}
          placeholder="Buscar por nome"
      <DataTable
        columns={columns}
        data={produtos}
        actions={(row) => (
          <div className="flex gap-2">
            <ActionButton variant="edit" onClick={() => onEdit(row)}>
              Editar
            </ActionButton>
            <ActionButton variant="delete" onClick={() => handleDelete(row.$id)}>
              Deletar
            </ActionButton>
        )}
      />

      <Pagination
        page={page}
        total={Math.ceil(total / 10) || 1}
        onPrev={onPrev}
        onNext={onNext}
      />
        >
          <option value="">Todos</option>
          {statusOptions.map(s => (
            <option key={s} value={s}>
              {s}
            </option>
          ))}
        </select>
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
          {error}
        </div>
      )}

      {loading ? (
        <div className="flex justify-center items-center min-h-screen">
          <div className="text-lg">Carregando pedidos...</div>
        </div>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={pedidos}
            actions={row => (
              <>
                <ActionButton variant="edit" onClick={() => onEdit(row)}>
                  ✏️ Editar
                </ActionButton>
                <ActionButton variant="delete" onClick={() => handleDelete(row.$id)}>
                  🗑️ Deletar
                </ActionButton>
              </>
            )}
          />

          <div className="mt-4 flex justify-between items-center">
            <div className="text-sm text-gray-600">
              {totalPedidos > 0 ? (
                <>Mostrando {startItem} - {endItem} de {totalPedidos} pedidos</>
              ) : (
                'Total de pedidos: 0'
              )}
            </div>

            <Pagination page={currentPage} total={totalPages} onPrev={onPrevPage} onNext={onNextPage} />
          </div>
        </>
      )}
    </div>
  );
};

export default PedidoList;


src/components/ProdutoForm.tsx

import React, { useState, useEffect } from 'react';
import { Models } from 'appwrite';
import { ProdutoData } from '@/hooks/useProdutos';

interface ProdutoFormProps {
  onSubmit: (data: ProdutoData) => Promise<boolean>;
  onCancel?: () => void;
  initialData?: Models.Document | null;
  loading?: boolean;
}

const ProdutoForm: React.FC<ProdutoFormProps> = ({
  onSubmit,
  onCancel,
  initialData,
  loading = false,
}) => {
  const [formData, setFormData] = useState<ProdutoData>({
    nome: '',
    'preco-original': 0,
    'preco-atual': 0,
    'catalogo-produto-id': '',
    'empresa-id': '',
  });
  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);

  useEffect(() => {
    if (initialData) {
      setFormData({
        nome: initialData.nome,
        'preco-original': initialData['preco-original'],
        'preco-atual': initialData['preco-atual'],
        'catalogo-produto-id': initialData['catalogo-produto-id'],
        'empresa-id': initialData['empresa-id'],
      });
    } else {
      setFormData({
        nome: '',
        'preco-original': 0,
        'preco-atual': 0,
        'catalogo-produto-id': '',
        'empresa-id': '',
      });
    }
  }, [initialData]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const success = await onSubmit(formData);
    if (success) {
      setMessage({
        type: 'success',
        text: initialData ? '🔄 Produto atualizado com sucesso!' : '🎉 Produto cadastrado com sucesso!'
      });
      if (!initialData) {
        setFormData({
          nome: '',
          'preco-original': 0,
          'preco-atual': 0,
          'catalogo-produto-id': '',
          'empresa-id': '',
        });
      }
      setTimeout(() => setMessage(null), 3000);
    } else {
      setMessage({ type: 'error', text: initialData ? 'Erro ao atualizar produto' : 'Erro ao cadastrar produto' });
    }
  };

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value, type } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: type === 'number' ? parseFloat(value) : value,
    }));
    if (message) setMessage(null);
  };

  return (
    <div className="bg-white rounded-lg shadow-md p-6">
      <div className="mb-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-2">
          {initialData ? '✏️ Editar Produto' : ' Novo Produto'}
        </h2>
        <p className="text-gray-600">
          {initialData ? 'Atualize os dados do produto.' : 'Cadastre um novo produto na plataforma SaveInMed.'}
        </p>
      </div>

      {message && (
        <div className={`mb-4 p-4 rounded-md ${message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'}`}>
          {message.text}
        </div>
      )}

      <form onSubmit={handleSubmit} className="space-y-6">
        <div>
          <label htmlFor="nome" className="block text-sm font-medium text-gray-700 mb-2">
            Nome do Produto *
          </label>
          <input
            type="text"
            id="nome"
            name="nome"
            value={formData.nome}
            onChange={handleChange}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="Ex: Paracetamol 500mg"
          />
        </div>
        <div>
          <label htmlFor="preco-original" className="block text-sm font-medium text-gray-700 mb-2">
            Preço Original *
          </label>
          <input
            type="number"
            id="preco-original"
            name="preco-original"
            value={formData['preco-original']}
            onChange={handleChange}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="Ex: 25.50"
          />
        </div>
        <div>
          <label htmlFor="preco-atual" className="block text-sm font-medium text-gray-700 mb-2">
            Preço Atual *
          </label>
          <input
            type="number"
            id="preco-atual"
            name="preco-atual"
            value={formData['preco-atual']}
            onChange={handleChange}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="Ex: 20.00"
          />
        </div>
        <div>
          <label htmlFor="catalogo-produto-id" className="block text-sm font-medium text-gray-700 mb-2">
            ID do Catálogo de Produto *
          </label>
          <input
            type="text"
            id="catalogo-produto-id"
            name="catalogo-produto-id"
            value={formData['catalogo-produto-id']}
            onChange={handleChange}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="Ex: 654321"
          />
        </div>
        <div>
          <label htmlFor="empresa-id" className="block text-sm font-medium text-gray-700 mb-2">
            ID da Empresa *
          </label>
          <input
            type="text"
            id="empresa-id"
            name="empresa-id"
            value={formData['empresa-id']}
            onChange={handleChange}
            required
            disabled={loading}
            className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
            placeholder="Ex: 123456"
          />
        </div>
        <div className="flex gap-4">
          <button
            type="submit"
            disabled={loading}
            className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
          >
            {loading ? '⏳ Processando...' : initialData ? '🔄 Atualizar' : ' Cadastrar'}
          </button>
          {onCancel && (
            <button
              type="button"
              onClick={onCancel}
              disabled={loading}
              className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
            >
               Cancelar
            </button>
          )}
        </div>
      </form>
    </div>
  );
};

export default ProdutoForm;


src/components/ProdutoList.tsx

import React from 'react';
import { Models } from 'appwrite';
import SearchBar from './SearchBar';
import RefreshButton from './RefreshButton';
import ListHeader from './ListHeader';
import DataTable, { Column } from './DataTable';
import Pagination from './Pagination';
import ActionButton from './ActionButton';

interface ProdutoListProps {
  produtos: Models.Document[];
  loading: boolean;
  error: string | null;
  totalProdutos: number;
  currentPage: number;
  pageSize: number;
  onEdit: (prod: Models.Document) => void;
  onDelete: (id: string) => Promise<boolean>;
  onRefresh: () => void;
  onPrevPage: () => void;
  onNextPage: () => void;
  onSearch: (nome: string) => void;
}

const ProdutoList: React.FC<ProdutoListProps> = ({
  produtos,
  loading,
  error,
  totalProdutos,
  currentPage,
  pageSize,
  onEdit,
  onDelete,
  onRefresh,
  onPrevPage,
  onNextPage,
  onSearch
}) => {
  const totalPages = Math.ceil(totalProdutos / pageSize);
  const startItem = (currentPage - 1) * pageSize + 1;
  const endItem = Math.min(currentPage * pageSize, totalProdutos);

  const [search, setSearch] = React.useState('');

  const handleSearch = () => {
    onSearch(search);
  };

  const handleDelete = async (id: string) => {
    if (confirm('Tem certeza que deseja deletar este produto?')) {
      await onDelete(id);
    }
  };

  const columns: Column<Models.Document>[] = [
    {
      key: 'preco-original',
      header: 'Preço Original',
      render: row => `R$ ${row['preco-original']?.toFixed?.(2) ?? row['preco-original']}`
    },
    {
      key: 'preco-atual',
      header: 'Preço Atual',
      render: row => `R$ ${row['preco-atual']?.toFixed?.(2) ?? row['preco-atual']}`
    },
    {
      key: 'catalogo-produtos',
      header: 'Catálogo',
      render: row => row['catalogo-produtos']?.descricao ?? row['catalogo-produto-id']
    },
    { key: 'empresa-id', header: 'Empresa' },
    { key: '$id', header: 'ID' }
  ];

  return (
    <div className="container mx-auto px-4 py-8">
      <ListHeader title="Lista de Produtos">
        <SearchBar
          value={search}
          onChange={setSearch}
          onSearch={handleSearch}
          placeholder="Buscar produto"
        />
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
          {error}
        </div>
      )}

      {loading ? (
        <div className="flex justify-center items-center min-h-screen">
          <div className="text-lg">Carregando produtos...</div>
        </div>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={produtos}
            actions={(prod) => (
              <>
                <ActionButton variant="edit" onClick={() => onEdit(prod)}>
                  ✏️ Editar
                </ActionButton>
                <ActionButton variant="delete" onClick={() => handleDelete(prod.$id)}>
                  🗑️ Deletar
                </ActionButton>
              </>
            )}
          />

          <div className="mt-4 flex justify-between items-center">
            <div className="text-sm text-gray-600">
              {totalProdutos > 0 ? (
                <>Mostrando {startItem} - {endItem} de {totalProdutos} produtos</>
              ) : (
                'Total de produtos: 0'
              )}
            </div>

            <Pagination
              page={currentPage}
              total={totalPages}
              onPrev={onPrevPage}
              onNext={onNextPage}
            />
          </div>
        </>
      )}
    </div>
  );
};

export default ProdutoList;


src/components/RefreshButton.tsx

import React from 'react';

type Props = {
  onClick: () => void;
  loading?: boolean;
};

const RefreshButton: React.FC<Props> = ({ onClick, loading }) => (
  <button
    onClick={onClick}
    disabled={loading}
    className="
      bg-blue-600 text-white px-4 py-2 rounded-md 
      hover:bg-blue-700 transition-colors duration-200
      inline-flex items-center h-10 gap-2
      disabled:opacity-50 disabled:cursor-not-allowed
      focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
      cursor-pointer
    "
  >
    {loading ? '⏳' : '🔄'} Atualizar
  </button>
);

export default RefreshButton;


src/components/SearchBar.tsx

import React from 'react';

type Props = {
  value: string;
  onChange: (val: string) => void;
  onSearch: () => void;
  placeholder?: string;
};

const SearchBar: React.FC<Props> = ({ value, onChange, onSearch, placeholder }) => {
  const handle = (e: React.FormEvent) => {
    e.preventDefault();
    onSearch();
  };

  return (
    <form onSubmit={handle} className="flex gap-2 items-center">
      <input
        type="text"
        value={value}
        onChange={e => onChange(e.target.value)}
        className="
          px-3 py-2 border border-gray-300 rounded-md 
          focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent
          placeholder-gray-500 mx-2 h-10
          text-gray-900 font-medium bg-white
        "
        placeholder={placeholder}
      />
      <button 
        type="submit" 
        className="
          bg-blue-600 text-white px-4 py-2 rounded-md 
          hover:bg-blue-700 transition-colors duration-200
          inline-flex items-center h-10 gap-2
          focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
          cursor-pointer
        "
      >
        🔍 Buscar
      </button>
    </form>
  );
};

export default SearchBar;


src/components/UsuarioForm.tsx

import React, { useState, useEffect } from 'react';
import { Models } from 'appwrite';
import { UsuarioFormData } from '@/hooks/useUsuarios';

interface UsuarioFormProps {
  onSubmit: (data: UsuarioFormData) => Promise<boolean>;
  onCancel?: () => void;
  initialData?: Models.Document | null;
  loading?: boolean;
}

const UsuarioForm: React.FC<UsuarioFormProps> = ({
  onSubmit,
  onCancel,
  initialData,
  loading = false,
}) => {
  const [formData, setFormData] = useState<UsuarioFormData>({
    'nome-civil': '',
    'nome-social': '',
    cpf: '',
    'auth-id-appwrite': '',
    enderecos: '',
    empresas: '',
    email: '',
  });
  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);

  useEffect(() => {
    if (initialData) {
      setFormData({
        'nome-civil': initialData['nome-civil'] || '',
        'nome-social': initialData['nome-social'] || '',
        cpf: initialData.cpf || '',
        'auth-id-appwrite': initialData['auth-id-appwrite'] || '',
        enderecos: initialData.enderecos || '',
        empresas: initialData.empresas || '',
        email: initialData.email || '',
      });
    } else {
      setFormData({
        'nome-civil': '',
        'nome-social': '',
        cpf: '',
        'auth-id-appwrite': '',
        enderecos: '',
        empresas: '',
        email: '',
      });
    }
  }, [initialData]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    const payload = { ...formData, cpf: formData.cpf.replace(/\D/g, '') };
    const success = await onSubmit(payload);

    if (success) {
      setMessage({
        type: 'success',
        text: initialData ? '🔄 Usuário atualizado com sucesso!' : '🎉 Usuário cadastrado com sucesso!',
      });

      if (!initialData) {
        setFormData({
          'nome-civil': '',
          'nome-social': '',
          cpf: '',
          'auth-id-appwrite': '',
          enderecos: '',
          empresas: '',
          email: '',
        });
      }

      setTimeout(() => setMessage(null), 3000);
    } else {
      setMessage({
        type: 'error',
        text: initialData ? 'Erro ao atualizar usuário' : 'Erro ao cadastrar usuário',
      });
    }
  };

  const formatCpf = (val: string) => {
    const digits = val.replace(/\D/g, '').slice(0, 11);
    return digits
      .replace(/(\d{3})(\d)/, '$1.$2')
      .replace(/(\d{3})(\d)/, '$1.$2')
      .replace(/(\d{3})(\d{1,2})$/, '$1-$2');
  };

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    const val = name === 'cpf' ? formatCpf(value) : value;
    setFormData(prev => ({ ...prev, [name]: val }));
    if (message) setMessage(null);
  };

  return (
    <div className="bg-white rounded-lg shadow-md p-6">
      <div className="mb-6">
        <h2 className="text-2xl font-bold text-gray-900 mb-2">
          {initialData ? '✏️ Editar Usuário' : ' Novo Usuário'}
        </h2>
        <p className="text-gray-600">
          {initialData ? 'Atualize os dados do usuário.' : 'Cadastre um novo usuário na plataforma SaveInMed.'}
        </p>
      </div>

      {message && (
        <div className={`mb-4 p-4 rounded-md ${
          message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'
        }`}
        >
          {message.text}
        </div>
      )}

      <form onSubmit={handleSubmit} className="space-y-6">
        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
          <div>
            <label htmlFor="nome-civil" className="block text-sm font-medium text-gray-700 mb-2">
              Nome Civil *
            </label>
            <input
              type="text"
              id="nome-civil"
              name="nome-civil"
              value={formData['nome-civil']}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="Digite o nome civil"
            />
          </div>
          <div>
            <label htmlFor="nome-social" className="block text-sm font-medium text-gray-700 mb-2">
              Nome Social *
            </label>
            <input
              type="text"
              id="nome-social"
              name="nome-social"
              value={formData['nome-social']}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="Digite o nome social"
            />
          </div>
          <div>
            <label htmlFor="cpf" className="block text-sm font-medium text-gray-700 mb-2">
              CPF *
            </label>
            <input
              type="text"
              id="cpf"
              name="cpf"
              value={formData.cpf}
              onChange={handleInputChange}
              required
              maxLength={11}
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="Digite o CPF"
            />
          </div>
          <div>
            <label htmlFor="auth-id-appwrite" className="block text-sm font-medium text-gray-700 mb-2">
              Auth ID (Appwrite) *
            </label>
            <input
              type="text"
              id="auth-id-appwrite"
              name="auth-id-appwrite"
              value={formData['auth-id-appwrite']}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="ID de autenticação"
            />
          </div>
          <div>
            <label htmlFor="enderecos" className="block text-sm font-medium text-gray-700 mb-2">
              Endereço (ID) *
            </label>
            <input
              type="text"
              id="enderecos"
              name="enderecos"
              value={formData.enderecos}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="ID do endereço"
            />
          </div>
          <div>
            <label htmlFor="empresas" className="block text-sm font-medium text-gray-700 mb-2">
              Empresa (ID) *
            </label>
            <input
              type="text"
              id="empresas"
              name="empresas"
              value={formData.empresas}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="ID da empresa"
            />
          </div>
          <div>
            <label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-2">
              Email *
            </label>
            <input
              type="email"
              id="email"
              name="email"
              value={formData.email}
              onChange={handleInputChange}
              required
              disabled={loading}
              className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
              placeholder="Digite o email"
            />
          </div>
        </div>

        <div className="flex gap-4">
          <button
            type="submit"
            disabled={loading}
            className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
          >
            {loading ? '⏳ Processando...' : initialData ? '🔄 Atualizar' : ' Cadastrar'}
          </button>

          {onCancel && (
            <button
              type="button"
              onClick={onCancel}
              disabled={loading}
              className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
            >
               Cancelar
            </button>
          )}
        </div>
      </form>
    </div>
  );
};

export default UsuarioForm;


src/components/UsuarioList.tsx

import React from 'react';
import { Models } from 'appwrite';
import SearchBar from './SearchBar';
import RefreshButton from './RefreshButton';
import ListHeader from './ListHeader';
import DataTable, { Column } from './DataTable';
import Pagination from './Pagination';
import ActionButton from './ActionButton';

interface UsuarioListProps {
  usuarios: Models.Document[];
  loading: boolean;
  error: string | null;
  totalUsuarios: number;
  currentPage: number;
  pageSize: number;
  onEdit: (user: Models.Document) => void;
  onDelete: (id: string) => Promise<boolean>;
  onRefresh: () => void;
  onPrevPage: () => void;
  onNextPage: () => void;
  onSearch: (term: string) => void;
}

const columns: Column<Models.Document>[] = [
  { key: 'nome-civil', header: 'Nome Civil' },
  { key: 'nome-social', header: 'Nome Social' },
  { key: 'email', header: 'Email' },
  {
    key: 'empresas',
    header: 'Empresa',
    render: row => {
      const empresa = (row as any).empresas;
      if (empresa && typeof empresa === 'object') {
        return (
          empresa['razao-social'] || empresa['nome-fantasia'] || empresa.$id || ''
        );
      }
      return empresa;
    },
  },
  { key: 'cpf', header: 'CPF' },
];

const UsuarioList: React.FC<UsuarioListProps> = ({
  usuarios,
  loading,
  error,
  totalUsuarios,
  currentPage,
  pageSize,
  onEdit,
  onDelete,
  onRefresh,
  onPrevPage,
  onNextPage,
  onSearch,
}) => {
  const [search, setSearch] = React.useState('');
  const totalPages = Math.ceil(totalUsuarios / pageSize);
  const startItem = (currentPage - 1) * pageSize + 1;
  const endItem = Math.min(currentPage * pageSize, totalUsuarios);

  const handleSearch = () => onSearch(search);

  const handleDelete = async (id: string) => {
    if (confirm('Tem certeza que deseja deletar este usuário?')) {
      await onDelete(id);
    }
  };

  return (
    <div className="container mx-auto px-4 py-8">
      <ListHeader title="Lista de Usuários">
        <SearchBar
          value={search}
          onChange={setSearch}
          onSearch={handleSearch}
          placeholder="Buscar nome ou email"
        />
        <RefreshButton onClick={onRefresh} loading={loading} />
      </ListHeader>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
          {error}
        </div>
      )}

      {loading ? (
        <div className="flex justify-center items-center min-h-screen">
          <div className="text-lg">Carregando usuários...</div>
        </div>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={usuarios}
            actions={(u) => (
              <>
                <ActionButton variant="edit" onClick={() => onEdit(u)}>
                  ✏️ Editar
                </ActionButton>
                <ActionButton variant="delete" onClick={() => handleDelete(u.$id)}>
                  🗑️ Deletar
                </ActionButton>
              </>
            )}
          />

          <div className="mt-4 flex justify-between items-center">
            <div className="text-sm text-gray-600">
              {totalUsuarios > 0 ? (
                <>Mostrando {startItem} - {endItem} de {totalUsuarios} usuários</>
              ) : (
                'Total de usuários: 0'
              )}
            </div>

            <Pagination
              page={currentPage}
              total={totalPages}
              onPrev={onPrevPage}
              onNext={onNextPage}
            />
          </div>
        </>
      )}
    </div>
  );
};

export default UsuarioList;


src/hooks/useCarrinhos.ts

import { useState, useCallback } from 'react';
import { Models } from 'appwrite';
import { carrinhoService } from '@/services/carrinhoService';

export interface CarrinhoFormData {
  usuarios: string;
  itens: string[];
  quantidade: number[];
}

export interface UseCarrinhosReturn {
  carrinhos: Models.Document[];
  loading: boolean;
  error: string | null;
  totalCarrinhos: number;
  currentPage: number;
  listarCarrinhos: (page?: number) => Promise<void>;
  buscarCarrinhos: (usuario: string, page?: number) => Promise<void>;
  cadastrarCarrinho: (data: CarrinhoFormData) => Promise<boolean>;
  atualizarCarrinho: (id: string, data: CarrinhoFormData) => Promise<boolean>;
  deletarCarrinho: (id: string) => Promise<boolean>;
  setCurrentPage: (page: number) => void;
}

const PAGE_SIZE = 10;

export const useCarrinhos = (): UseCarrinhosReturn => {
  const [carrinhos, setCarrinhos] = useState<Models.Document[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [totalCarrinhos, setTotalCarrinhos] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);

  const listarCarrinhos = useCallback(async (page = currentPage) => {
    setLoading(true);
    setError(null);

    try {
      const response = await carrinhoService.listar(page, PAGE_SIZE);

      if (response.success) {
        setCarrinhos(response.documents || []);
        setTotalCarrinhos(response.total || 0);
        setCurrentPage(page);
      } else {
        setError(response.error || 'Erro ao carregar carrinhos');
      }
    } catch (err) {
      setError('Erro de conexão ao carregar carrinhos');
    } finally {
      setLoading(false);
    }
  }, [currentPage]);

  const buscarCarrinhos = useCallback(
    async (usuario: string, page = 1) => {
      setLoading(true);
      setError(null);

      try {
        const response = await carrinhoService.buscarPorUsuario(
          usuario,
          page,
          PAGE_SIZE
        );

        if (response.success) {
          setCarrinhos(response.documents || []);
          setTotalCarrinhos(response.total || 0);
          setCurrentPage(page);
        } else {
          setError(response.error || 'Erro ao buscar carrinhos');
        }
      } catch (err) {
        setError('Erro de conexão ao buscar carrinhos');
      } finally {
        setLoading(false);
      }
    },
    []
  );

  const cadastrarCarrinho = useCallback(async (formData: CarrinhoFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await carrinhoService.criar(formData);

      if (response.success) {
        await listarCarrinhos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao cadastrar carrinho');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao cadastrar carrinho');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarCarrinhos]);

  const atualizarCarrinho = useCallback(async (id: string, formData: CarrinhoFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await carrinhoService.atualizar(id, formData);

      if (response.success) {
        await listarCarrinhos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao atualizar carrinho');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao atualizar carrinho');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarCarrinhos]);

  const deletarCarrinho = useCallback(async (id: string): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await carrinhoService.deletar(id);

      if (response.success) {
        await listarCarrinhos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao deletar carrinho');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao deletar carrinho');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarCarrinhos]);

  return {
    carrinhos,
    loading,
    error,
    totalCarrinhos,
    currentPage,
    listarCarrinhos,
    buscarCarrinhos,
    cadastrarCarrinho,
    atualizarCarrinho,
    deletarCarrinho,
    setCurrentPage,
  };
};


src/hooks/useCatalogoProdutos.ts

import { useState, useCallback } from 'react';
import { Models } from 'appwrite';
import { catalogoProdutoService } from '@/services/catalogoProdutoService';

export interface CatalogoProdutoFormData {
  nome: string;
}

export interface UseCatalogoProdutosReturn {
  catalogoProdutos: Models.Document[];
  loading: boolean;
  error: string | null;
  totalCatalogoProdutos: number;
  currentPage: number;
  listarCatalogo: (page?: number) => Promise<void>;
  buscarCatalogo: (nome: string, page?: number) => Promise<void>;
  cadastrarCatalogo: (data: CatalogoProdutoFormData) => Promise<boolean>;
  atualizarCatalogo: (id: string, data: CatalogoProdutoFormData) => Promise<boolean>;
  deletarCatalogo: (id: string) => Promise<boolean>;
  setCurrentPage: (page: number) => void;
}

const PAGE_SIZE = 10;

export const useCatalogoProdutos = (): UseCatalogoProdutosReturn => {
  const [catalogoProdutos, setCatalogoProdutos] = useState<Models.Document[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [totalCatalogoProdutos, setTotalCatalogoProdutos] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);

  // Listagem usando SDK do Appwrite
  const listarCatalogo = useCallback(async (page = currentPage) => {
    setLoading(true);
    setError(null);

    try {
      const response = await catalogoProdutoService.listar(page, PAGE_SIZE);

      if (response.success) {
        setCatalogoProdutos(response.documents || []);
        setTotalCatalogoProdutos(response.total || 0);
        setCurrentPage(page);
      } else {
        setError(response.error || 'Erro ao carregar catálogos de produtos');
      }
    } catch (err) {
      setError('Erro de conexão ao carregar catálogos de produtos');
    } finally {
      setLoading(false);
    }
  }, [currentPage]);

  const buscarCatalogo = useCallback(
    async (nome: string, page = 1) => {
      setLoading(true);
      setError(null);

      try {
        const response = await catalogoProdutoService.buscarPorNome(
          nome,
          page,
          PAGE_SIZE
        );

        if (response.success) {
          setCatalogoProdutos(response.documents || []);
          setTotalCatalogoProdutos(response.total || 0);
          setCurrentPage(page);
        } else {
          setError(response.error || 'Erro ao buscar catálogos de produtos');
        }
      } catch (err) {
        setError('Erro de conexão ao buscar catálogos de produtos');
      } finally {
        setLoading(false);
      }
    },
    []
  );

  // Operações de criação, atualização e exclusão continuam usando API REST
  const cadastrarCatalogo = useCallback(async (formData: CatalogoProdutoFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await catalogoProdutoService.criar(formData);

      if (response.success) {
        await listarCatalogo(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao cadastrar catálogo de produto');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao cadastrar catálogo de produto');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarCatalogo]);

  const atualizarCatalogo = useCallback(async (id: string, formData: CatalogoProdutoFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await catalogoProdutoService.atualizar(id, formData);

      if (response.success) {
        await listarCatalogo(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao atualizar catálogo de produto');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao atualizar catálogo de produto');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarCatalogo]);

  const deletarCatalogo = useCallback(async (id: string): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await catalogoProdutoService.deletar(id);

      if (response.success) {
        await listarCatalogo(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao deletar catálogo de produto');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao deletar catálogo de produto');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarCatalogo]);

  return {
    catalogoProdutos,
    loading,
    error,
    totalCatalogoProdutos,
    currentPage,
    listarCatalogo,
    buscarCatalogo,
    cadastrarCatalogo,
    atualizarCatalogo,
    deletarCatalogo,
    setCurrentPage,
  };
};



src/hooks/useCategorias.ts

import { useState, useCallback } from 'react';
import { Models } from 'appwrite';
import { categoriaService } from '@/services/categoriaService';

export interface CategoriaFormData {
  nome: string;
}

export interface UseCategoriasReturn {
  categorias: Models.Document[];
  loading: boolean;
  error: string | null;
  totalCategorias: number;
  currentPage: number;
  listarCategorias: (page?: number) => Promise<void>;
  buscarCategorias: (nome: string, page?: number) => Promise<void>;
  cadastrarCategoria: (data: CategoriaFormData) => Promise<boolean>;
  atualizarCategoria: (id: string, data: CategoriaFormData) => Promise<boolean>;
  deletarCategoria: (id: string) => Promise<boolean>;
  setCurrentPage: (page: number) => void;
}

const PAGE_SIZE = 10;

export const useCategorias = (): UseCategoriasReturn => {
  const [categorias, setCategorias] = useState<Models.Document[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [totalCategorias, setTotalCategorias] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);

  // Listagem via API
  const listarCategorias = useCallback(async (page = currentPage) => {
    setLoading(true);
    setError(null);

    try {
      const response = await categoriaService.listar(page, PAGE_SIZE);

      if (response.success) {
        setCategorias(response.documents || []);
        setTotalCategorias(response.total || 0);
        setCurrentPage(page);
      } else {
        setError(response.error || 'Erro ao carregar categorias');
      }
    } catch (err) {
      setError('Erro de conexão ao carregar categorias');
    } finally {
      setLoading(false);
    }
  }, [currentPage]);

  const buscarCategorias = useCallback(
    async (nome: string, page = 1) => {
      setLoading(true);
      setError(null);

      try {
        const response = await categoriaService.buscarPorNome(
          nome,
          page,
          PAGE_SIZE
        );

        if (response.success) {
          setCategorias(response.documents || []);
          setTotalCategorias(response.total || 0);
          setCurrentPage(page);
        } else {
          setError(response.error || 'Erro ao buscar categorias');
        }
      } catch (err) {
        setError('Erro de conexão ao buscar categorias');
      } finally {
        setLoading(false);
      }
    },
    []
  );

  // Operações de criação, atualização e exclusão continuam usando API REST
  const cadastrarCategoria = useCallback(async (formData: CategoriaFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await categoriaService.criar(formData);

      if (response.success) {
        await listarCategorias(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao cadastrar categoria');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao cadastrar categoria');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarCategorias]);

  const atualizarCategoria = useCallback(async (id: string, formData: CategoriaFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await categoriaService.atualizar(id, formData);

      if (response.success) {
        await listarCategorias(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao atualizar categoria');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao atualizar categoria');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarCategorias]);

  const deletarCategoria = useCallback(async (id: string): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await categoriaService.deletar(id);

      if (response.success) {
        await listarCategorias(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao deletar categoria');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao deletar categoria');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarCategorias]);

  return {
    categorias,
    loading,
    error,
    totalCategorias,
    currentPage,
    listarCategorias,
    buscarCategorias,
    cadastrarCategoria,
    atualizarCategoria,
    deletarCategoria,
    setCurrentPage,
  };
};

src/hooks/useEnderecos.ts

import { useState, useCallback } from 'react';
import { Models } from 'appwrite';
import { enderecoService, EnderecoData } from '@/services/enderecoService';
export type { EnderecoData };

export interface UseEnderecosReturn {
  enderecos: Models.Document[];
  loading: boolean;
  error: string | null;
  totalEnderecos: number;
  currentPage: number;
  listarEnderecos: (page?: number) => Promise<void>;
  buscarEnderecos: (termo: string, page?: number) => Promise<void>;
  cadastrarEndereco: (data: EnderecoData) => Promise<boolean>;
  atualizarEndereco: (id: string, data: EnderecoData) => Promise<boolean>;
  deletarEndereco: (id: string) => Promise<boolean>;
  setCurrentPage: (page: number) => void;
}

const PAGE_SIZE = 10;

export const useEnderecos = (): UseEnderecosReturn => {
  const [enderecos, setEnderecos] = useState<Models.Document[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [totalEnderecos, setTotalEnderecos] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);

  const listarEnderecos = useCallback(async (page = currentPage) => {
    setLoading(true);
    setError(null);

    try {
      const response = await enderecoService.listar(page, PAGE_SIZE);

      if (response.success) {
        setEnderecos(response.documents || []);
        setTotalEnderecos(response.total || 0);
        setCurrentPage(page);
      } else {
        setError(response.error || 'Erro ao carregar endereços');
      }
    } catch (err) {
      setError('Erro de conexão ao carregar endereços');
    } finally {
      setLoading(false);
    }
  }, [currentPage]);

  const buscarEnderecos = useCallback(
    async (termo: string, page = 1) => {
      setLoading(true);
      setError(null);

      try {
        const response = await enderecoService.buscar(
          termo,
          page,
          PAGE_SIZE
        );

        if (response.success) {
          setEnderecos(response.documents || []);
          setTotalEnderecos(response.total || 0);
          setCurrentPage(page);
        } else {
          setError(response.error || 'Erro ao buscar enderecos');
        }
      } catch (err) {
        setError('Erro de conexão ao buscar enderecos');
      } finally {
        setLoading(false);
      }
    },
    []
  );

  const cadastrarEndereco = useCallback(async (formData: EnderecoData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await enderecoService.criar(formData);

      if (response.success) {
        await listarEnderecos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao cadastrar endereço');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao cadastrar endereço');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarEnderecos]);

  const atualizarEndereco = useCallback(async (id: string, formData: EnderecoData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await enderecoService.atualizar(id, formData);

      if (response.success) {
        await listarEnderecos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao atualizar endereço');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao atualizar endereço');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarEnderecos]);

  const deletarEndereco = useCallback(async (id: string): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await enderecoService.deletar(id);

      if (response.success) {
        await listarEnderecos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao deletar endereço');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao deletar endereço');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarEnderecos]);

  return {
    enderecos,
    loading,
    error,
    totalEnderecos,
    currentPage,
    listarEnderecos,
    buscarEnderecos,
    cadastrarEndereco,
    atualizarEndereco,
    deletarEndereco,
    setCurrentPage,
  };
};


src/hooks/useFaturas.ts

import { useState, useCallback } from 'react';
import { Models } from 'appwrite';
import { faturaService } from '@/services/faturaService';

export interface FaturaFormData {
  nome: string;
}

export interface UseFaturasReturn {
  faturas: Models.Document[];
  loading: boolean;
  error: string | null;
  totalFaturas: number;
  currentPage: number;
  listarFaturas: (page?: number) => Promise<void>;
  buscarFaturas: (nome: string, page?: number) => Promise<void>;
  cadastrarFatura: (data: FaturaFormData) => Promise<boolean>;
  atualizarFatura: (id: string, data: FaturaFormData) => Promise<boolean>;
  deletarFatura: (id: string) => Promise<boolean>;
  setCurrentPage: (page: number) => void;
}

const PAGE_SIZE = 10;

export const useFaturas = (): UseFaturasReturn => {
  const [faturas, setFaturas] = useState<Models.Document[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [totalFaturas, setTotalFaturas] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);

  // Listagem usando SDK do Appwrite
  const listarFaturas = useCallback(async (page = currentPage) => {
    setLoading(true);
    setError(null);

    try {
      const response = await faturaService.listar(page, PAGE_SIZE);

      if (response.success) {
        setFaturas(response.documents || []);
        setTotalFaturas(response.total || 0);
        setCurrentPage(page);
      } else {
        setError(response.error || 'Erro ao carregar faturas');
      }
    } catch (err) {
      setError('Erro de conexão ao carregar faturas');
    } finally {
      setLoading(false);
    }
  }, [currentPage]);

  const buscarFaturas = useCallback(
    async (nome: string, page = 1) => {
      setLoading(true);
      setError(null);

      try {
        const response = await faturaService.buscarPorNome(
          nome,
          page,
          PAGE_SIZE
        );

        if (response.success) {
          setFaturas(response.documents || []);
          setTotalFaturas(response.total || 0);
          setCurrentPage(page);
        } else {
          setError(response.error || 'Erro ao buscar faturas');
        }
      } catch (err) {
        setError('Erro de conexão ao buscar faturas');
      } finally {
        setLoading(false);
      }
    },
    []
  );

  // Operações de criação, atualização e exclusão continuam usando API REST
  const cadastrarFatura = useCallback(async (formData: FaturaFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await faturaService.criar(formData);

      if (response.success) {
        await listarFaturas(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao cadastrar fatura');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao cadastrar fatura');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarFaturas]);

  const atualizarFatura = useCallback(async (id: string, formData: FaturaFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await faturaService.atualizar(id, formData);

      if (response.success) {
        await listarFaturas(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao atualizar fatura');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao atualizar fatura');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarFaturas]);

  const deletarFatura = useCallback(async (id: string): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await faturaService.deletar(id);

      if (response.success) {
        await listarFaturas(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao deletar fatura');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao deletar fatura');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarFaturas]);

  return {
    faturas,
    loading,
    error,
    totalFaturas,
    currentPage,
    listarFaturas,
    buscarFaturas,
    cadastrarFatura,
    atualizarFatura,
    deletarFatura,
    setCurrentPage,
  };
};


src/hooks/useLaboratorios.ts

import { useState, useCallback } from 'react';
import { Models } from 'appwrite';
import { laboratorioService } from '@/services/laboratorioService';

export interface LaboratorioFormData {
  nome: string;
}

export interface UseLaboratoriosReturn {
  laboratorios: Models.Document[];
  loading: boolean;
  error: string | null;
  totalLaboratorios: number;
  currentPage: number;
  listarLaboratorios: (page?: number) => Promise<void>;
  buscarLaboratorios: (nome: string, page?: number) => Promise<void>;
  cadastrarLaboratorio: (data: LaboratorioFormData) => Promise<boolean>;
  atualizarLaboratorio: (id: string, data: LaboratorioFormData) => Promise<boolean>;
  deletarLaboratorio: (id: string) => Promise<boolean>;
  setCurrentPage: (page: number) => void;
}

const PAGE_SIZE = 10;

export const useLaboratorios = (): UseLaboratoriosReturn => {
  const [laboratorios, setLaboratorios] = useState<Models.Document[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [totalLaboratorios, setTotalLaboratorios] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);

  // Listagem usando SDK do Appwrite
  const listarLaboratorios = useCallback(async (page = currentPage) => {
    setLoading(true);
    setError(null);

    try {
      const response = await laboratorioService.listar(page, PAGE_SIZE);

      if (response.success) {
        setLaboratorios(response.documents || []);
        setTotalLaboratorios(response.total || 0);
        setCurrentPage(page);
      } else {
        setError(response.error || 'Erro ao carregar laboratórios');
      }
    } catch (err) {
      setError('Erro de conexão ao carregar laboratórios');
    } finally {
      setLoading(false);
    }
  }, [currentPage]);

  const buscarLaboratorios = useCallback(
    async (nome: string, page = 1) => {
      setLoading(true);
      setError(null);

      try {
        const response = await laboratorioService.buscarPorNome(
          nome,
          page,
          PAGE_SIZE
        );

        if (response.success) {
          setLaboratorios(response.documents || []);
          setTotalLaboratorios(response.total || 0);
          setCurrentPage(page);
        } else {
          setError(response.error || 'Erro ao buscar laboratórios');
        }
      } catch (err) {
        setError('Erro de conexão ao buscar laboratórios');
      } finally {
        setLoading(false);
      }
    },
    []
  );

  // Operações de criação, atualização e exclusão continuam usando API REST
  const cadastrarLaboratorio = useCallback(async (formData: LaboratorioFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await laboratorioService.criar(formData);

      if (response.success) {
        await listarLaboratorios(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao cadastrar laboratório');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao cadastrar laboratório');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarLaboratorios]);

  const atualizarLaboratorio = useCallback(async (id: string, formData: LaboratorioFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await laboratorioService.atualizar(id, formData);

      if (response.success) {
        await listarLaboratorios(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao atualizar laboratório');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao atualizar laboratório');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarLaboratorios]);

  const deletarLaboratorio = useCallback(async (id: string): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await laboratorioService.deletar(id);

      if (response.success) {
        await listarLaboratorios(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao deletar laboratório');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao deletar laboratório');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarLaboratorios]);

  return {
    laboratorios,
    loading,
    error,
    totalLaboratorios,
    currentPage,
    listarLaboratorios,
    buscarLaboratorios,
    cadastrarLaboratorio,
    atualizarLaboratorio,
    deletarLaboratorio,
    setCurrentPage,
  };
};

src/hooks/usePagamentos.ts

import { useState, useCallback } from 'react';
import { Models } from 'appwrite';
import { pagamentoService, PagamentoData } from '@/services/pagamentoService';
export type { PagamentoData };

export interface UsePagamentosReturn {
  pagamentos: Models.Document[];
  loading: boolean;
  error: string | null;
  totalPagamentos: number;
  currentPage: number;
  listarPagamentos: (page?: number, search?: string) => Promise<void>;
  cadastrarPagamento: (data: PagamentoData) => Promise<boolean>;
  atualizarPagamento: (id: string, data: PagamentoData) => Promise<boolean>;
  deletarPagamento: (id: string) => Promise<boolean>;
  setCurrentPage: (page: number) => void;
}

const PAGE_SIZE = 10;

export const usePagamentos = (): UsePagamentosReturn => {
  const [pagamentos, setPagamentos] = useState<Models.Document[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [totalPagamentos, setTotalPagamentos] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);

  const listarPagamentos = useCallback(
    async (page = currentPage, search = '') => {
    setLoading(true);
    setError(null);

    try {
      const response = await pagamentoService.listar(page, PAGE_SIZE, search);

      if (response.success) {
        setPagamentos((response.documents as unknown as Models.Document[]) || []);
        setTotalPagamentos(response.total || 0);
        setCurrentPage(page);
      } else {
        setError(response.error || 'Erro ao carregar pagamentos');
      }
    } catch (err) {
      setError('Erro de conexão ao carregar pagamentos');
    } finally {
      setLoading(false);
    }
  }, [currentPage]);

  const cadastrarPagamento = useCallback(async (formData: PagamentoData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await pagamentoService.criar(formData);

      if (response.success) {
        await listarPagamentos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao cadastrar pagamento');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao cadastrar pagamento');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarPagamentos]);

  const atualizarPagamento = useCallback(async (id: string, formData: PagamentoData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await pagamentoService.atualizar(id, formData);

      if (response.success) {
        await listarPagamentos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao atualizar pagamento');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao atualizar pagamento');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarPagamentos]);

  const deletarPagamento = useCallback(async (id: string): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await pagamentoService.deletar(id);

      if (response.success) {
        await listarPagamentos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao deletar pagamento');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao deletar pagamento');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarPagamentos]);

  return {
    pagamentos,
    loading,
    error,
    totalPagamentos,
    currentPage,
    listarPagamentos,
    cadastrarPagamento,
    atualizarPagamento,
    deletarPagamento,
    setCurrentPage,
  };
};


src/hooks/usePedidos.ts

import { useState, useCallback } from 'react';
import { Models } from 'appwrite';
import { pedidoService, PedidoData } from '@/services/pedidoService';
export type { PedidoData };

export const PAGE_SIZE = 10;

export const usePedidos = () => {
  const [pedidos, setPedidos] = useState<Models.Document[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [totalPedidos, setTotalPedidos] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);

  const listarPedidos = useCallback(
    async (page = currentPage, status = '', search = '') => {
      setLoading(true);
      setError(null);
      try {
        const response = await pedidoService.listar(page, PAGE_SIZE, status, search);
        if (response.success) {
          setPedidos((response.documents as unknown as Models.Document[]) || []);
          setTotalPedidos(response.total || 0);
          setCurrentPage(page);
        } else {
          setError(response.error || 'Erro ao carregar pedidos');
        }
      } catch (err) {
        setError('Erro de conexão ao carregar pedidos');
      } finally {
        setLoading(false);
      }
    },
    [currentPage]
  );

  const cadastrarPedido = useCallback(
    async (formData: PedidoData): Promise<boolean> => {
      setLoading(true);
      setError(null);
      try {
        const response = await pedidoService.criar(formData);
        if (response.success) {
          await listarPedidos(currentPage);
          return true;
        } else {
          setError(response.error || 'Erro ao cadastrar pedido');
          return false;
        }
      } catch (err) {
        setError('Erro de conexão ao cadastrar pedido');
        return false;
      } finally {
        setLoading(false);
      }
    },
    [currentPage, listarPedidos]
  );

  const atualizarPedido = useCallback(
    async (id: string, formData: PedidoData): Promise<boolean> => {
      setLoading(true);
      setError(null);
      try {
        const response = await pedidoService.atualizar(id, formData);
        if (response.success) {
          await listarPedidos(currentPage);
          return true;
        } else {
          setError(response.error || 'Erro ao atualizar pedido');
          return false;
        }
      } catch (err) {
        setError('Erro de conexão ao atualizar pedido');
        return false;
      } finally {
        setLoading(false);
      }
    },
    [currentPage, listarPedidos]
  );

  const deletarPedido = useCallback(
    async (id: string): Promise<boolean> => {
      setLoading(true);
      setError(null);
      try {
        const response = await pedidoService.deletar(id);
        if (response.success) {
          await listarPedidos(currentPage);
          return true;
        } else {
          setError(response.error || 'Erro ao deletar pedido');
          return false;
        }
      } catch (err) {
        setError('Erro de conexão ao deletar pedido');
        return false;
      } finally {
        setLoading(false);
      }
    },
    [currentPage, listarPedidos]
  );

  return {
    pedidos,
    loading,
    error,
    totalPedidos,
    currentPage,
    listarPedidos,
    cadastrarPedido,
    atualizarPedido,
    deletarPedido,
    setCurrentPage,
  };
};


src/hooks/useProdutos.ts

import { useState, useCallback } from 'react';
import { Models } from 'appwrite';
import { produtoService, ProdutoData } from '@/services/produtoService';
export type { ProdutoData };

export interface UseProdutosReturn {
  produtos: Models.Document[];
  loading: boolean;
  error: string | null;
  totalProdutos: number;
  currentPage: number;
  listarProdutos: (page?: number) => Promise<void>;
  buscarProdutos: (nome: string, page?: number) => Promise<void>;
  cadastrarProduto: (data: ProdutoData) => Promise<boolean>;
  atualizarProduto: (id: string, data: ProdutoData) => Promise<boolean>;
  deletarProduto: (id: string) => Promise<boolean>;
  setCurrentPage: (page: number) => void;
}

const PAGE_SIZE = 10;

export const useProdutos = (): UseProdutosReturn => {
  const [produtos, setProdutos] = useState<Models.Document[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [totalProdutos, setTotalProdutos] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);

  const listarProdutos = useCallback(async (page = currentPage) => {
    setLoading(true);
    setError(null);

    try {
      const response = await produtoService.listar(page, PAGE_SIZE);

      if (response.success) {
        setProdutos(response.documents || []);
        setTotalProdutos(response.total || 0);
        setCurrentPage(page);
      } else {
        setError(response.error || 'Erro ao carregar produtos');
      }
    } catch (err) {
      setError('Erro de conexão ao carregar produtos');
    } finally {
      setLoading(false);
    }
  }, [currentPage]);

  const buscarProdutos = useCallback(async (_nome: string, page = 1) => {
    await listarProdutos(page);
  }, [listarProdutos]);

  const cadastrarProduto = useCallback(async (formData: ProdutoData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await produtoService.criar(formData);

      if (response.success) {
        await listarProdutos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao cadastrar produto');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao cadastrar produto');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarProdutos]);

  const atualizarProduto = useCallback(async (id: string, formData: ProdutoData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await produtoService.atualizar(id, formData);

      if (response.success) {
        await listarProdutos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao atualizar produto');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao atualizar produto');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarProdutos]);

  const deletarProduto = useCallback(async (id: string): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await produtoService.deletar(id);

      if (response.success) {
        await listarProdutos(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao deletar produto');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao deletar produto');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarProdutos]);

  return {
    produtos,
    loading,
    error,
    totalProdutos,
    currentPage,
    listarProdutos,
    buscarProdutos,
    cadastrarProduto,
    atualizarProduto,
    deletarProduto,
    setCurrentPage,
  };
};


src/hooks/useUsuarios.ts

import { useState, useCallback } from 'react';
import { Models } from 'appwrite';
import { usuarioService, UsuarioData } from '@/services/usuarioService';

export interface UsuarioFormData extends UsuarioData {}

export interface UseUsuariosReturn {
  usuarios: Models.Document[];
  loading: boolean;
  error: string | null;
  totalUsuarios: number;
  currentPage: number;
  listarUsuarios: (page?: number) => Promise<void>;
  buscarUsuarios: (nome: string, page?: number) => Promise<void>;
  cadastrarUsuario: (data: UsuarioFormData) => Promise<boolean>;
  atualizarUsuario: (id: string, data: UsuarioFormData) => Promise<boolean>;
  deletarUsuario: (id: string) => Promise<boolean>;
  setCurrentPage: (page: number) => void;
}

const PAGE_SIZE = 10;

export const useUsuarios = (): UseUsuariosReturn => {
  const [usuarios, setUsuarios] = useState<Models.Document[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [totalUsuarios, setTotalUsuarios] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);

  const listarUsuarios = useCallback(async (page = currentPage) => {
    setLoading(true);
    setError(null);

    try {
      const response = await usuarioService.listar(page, PAGE_SIZE);

      if (response.success) {
        setUsuarios(response.documents || []);
        setTotalUsuarios(response.total || 0);
        setCurrentPage(page);
      } else {
        setError(response.error || 'Erro ao carregar usuários');
      }
    } catch (err) {
      setError('Erro de conexão ao carregar usuários');
    } finally {
      setLoading(false);
    }
  }, [currentPage]);

  const buscarUsuarios = useCallback(async (nome: string, page = 1) => {
    setLoading(true);
    setError(null);

    try {
      const response = await usuarioService.buscarPorNome(nome, page, PAGE_SIZE);

      if (response.success) {
        setUsuarios(response.documents || []);
        setTotalUsuarios(response.total || 0);
        setCurrentPage(page);
      } else {
        setError(response.error || 'Erro ao buscar usuários');
      }
    } catch (err) {
      setError('Erro de conexão ao buscar usuários');
    } finally {
      setLoading(false);
    }
  }, []);

  const cadastrarUsuario = useCallback(async (formData: UsuarioFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await usuarioService.criar(formData);

      if (response.success) {
        await listarUsuarios(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao cadastrar usuário');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao cadastrar usuário');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarUsuarios]);

  const atualizarUsuario = useCallback(async (id: string, formData: UsuarioFormData): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await usuarioService.atualizar(id, formData);

      if (response.success) {
        await listarUsuarios(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao atualizar usuário');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao atualizar usuário');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarUsuarios]);

  const deletarUsuario = useCallback(async (id: string): Promise<boolean> => {
    setLoading(true);
    setError(null);

    try {
      const response = await usuarioService.deletar(id);

      if (response.success) {
        await listarUsuarios(currentPage);
        return true;
      } else {
        setError(response.error || 'Erro ao deletar usuário');
        return false;
      }
    } catch (err) {
      setError('Erro de conexão ao deletar usuário');
      return false;
    } finally {
      setLoading(false);
    }
  }, [currentPage, listarUsuarios]);

  return {
    usuarios,
    loading,
    error,
    totalUsuarios,
    currentPage,
    listarUsuarios,
    buscarUsuarios,
    cadastrarUsuario,
    atualizarUsuario,
    deletarUsuario,
    setCurrentPage,
  };
};


src/lib/appwrite.ts

// lib/appwrite.ts
import { Client, Account, ID, Databases, Functions } from 'appwrite';

/**
 * O objeto `client` será compartilhado em toda a aplicação.
 * Caso esteja em SSR (Next.js, Remix, etc.), ele só cria uma instância.
 */
let appwriteClient: Client | null = null;

function getClient(): Client {
    if (!appwriteClient) {
        const endpoint = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT ?? 'http://localhost';
        const project = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID ?? 'development';
        appwriteClient = new Client()
            .setEndpoint(endpoint)
            .setProject(project);
    }
    return appwriteClient;
}

export const client = getClient();
export const account = new Account(client);
export const databases = new Databases(client); // 🆕 Adicionar SDK de databases
export const functions = new Functions(client);

/**
 * Reexporta `ID` para criar documentos, usuários, etc.
 * Ex.: databases.createDocument(DB_ID, COL_ID, ID.unique(), data)
 */
export { ID };


src/modules/faturas/pages/[id]/edit.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter, useParams } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import FaturaForm from '@/components/FaturaForm';
import { useFaturas, FaturaFormData } from '@/hooks/useFaturas';
import { faturaService } from '@/services/faturaService';


export default function EditFaturaPage() {
  const router = useRouter();
  const params = useParams();
  const id = Array.isArray(params.id) ? params.id[0] : params.id;
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [doc, setDoc] = useState<Models.Document | null>(null);
  const { atualizarFatura, loading } = useFaturas();

  useEffect(() => {
    account
      .get()
      .then(setUser)
      .catch(() => router.push('/'));
  }, [router]);

  useEffect(() => {
    if (id) {
      faturaService.obterPorId(id).then(res => {
        if (res.success) setDoc(res.data as Models.Document);
      });
    }
  }, [id]);

  const handleSubmit = async (data: FaturaFormData) => {
    if (!id) return false;
    const success = await atualizarFatura(id as string, data);
    if (success) router.push('/modules/faturas');
    return success;
  };

  if (!user || !doc) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4" />
          <p className="text-gray-600">Carregando...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header user={user} title="Editar Fatura" subtitle={id} />
      <main className="max-w-2xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        <FaturaForm initialData={doc} onSubmit={handleSubmit} loading={loading} onCancel={() => router.push('/modules/faturas')} />
      </main>
    </div>
  );
}


src/modules/faturas/pages/index.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import FaturaList from '@/components/FaturaList';
import { useFaturas } from '@/hooks/useFaturas';

const STATUS_OPTIONS = ['pendente', 'paga', 'cancelada'];

export default function FaturasPage() {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const [statusFilter, setStatusFilter] = useState('');
  const [searchTerm, setSearchTerm] = useState('');

  const {
    faturas,
    loading,
    error,
    totalFaturas,
    currentPage,
    listarFaturas,
    buscarFaturas,
    deletarFatura,
  } = useFaturas();

  useEffect(() => {
    account
      .get()
      .then(setUser)
      .catch(() => router.push('/'));
  }, [router]);

  useEffect(() => {
    listarFaturas();
  }, [listarFaturas]);

  const handleEdit = (fat: Models.Document) => {
    router.push(`/modules/faturas/${fat.$id}/edit`);
  };

  const handlePrevPage = async () => {
    if (currentPage > 1) {
      await listarFaturas(currentPage - 1);
    }
  };

  const handleNextPage = async () => {
    const totalPages = Math.ceil(totalFaturas / 10);
    if (currentPage < totalPages) {
      await listarFaturas(currentPage + 1);
    }
  };

  const handleSearch = async (term: string) => {
    setSearchTerm(term);
    if (term.trim()) {
      await buscarFaturas(term, 1);
    } else {
      await listarFaturas(1);
    }
  };

  const filtered = statusFilter
    ? faturas.filter(f => f.status === statusFilter)
    : faturas;

  if (!user) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4" />
          <p className="text-gray-600">Verificando autenticação...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header user={user} title="Faturas" subtitle="Lista de Faturas" />
      <main className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        <div className="mb-4 flex gap-2">
          <select
            value={statusFilter}
            onChange={e => setStatusFilter(e.target.value)}
            className="px-3 py-2 border border-gray-300 rounded-md bg-white text-gray-900"
          >
            <option value="">Todos</option>
            {STATUS_OPTIONS.map(opt => (
              <option key={opt} value={opt}>
                {opt}
              </option>
            ))}
          </select>
          <button
            className="px-3 py-2 bg-blue-600 text-white rounded-md"
            onClick={() => router.push('/modules/faturas/new')}
          >
             Nova Fatura
          </button>
        </div>
        <FaturaList
          faturas={filtered}
          loading={loading}
          error={error}
          totalFaturas={totalFaturas}
          currentPage={currentPage}
          pageSize={10}
          onEdit={handleEdit}
          onDelete={deletarFatura}
          onRefresh={() => listarFaturas(currentPage)}
          onPrevPage={handlePrevPage}
          onNextPage={handleNextPage}
          onSearch={handleSearch}
        />
      </main>
    </div>
  );
}


src/modules/faturas/pages/new.tsx

'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { account } from '@/lib/appwrite';
import { Models } from 'appwrite';
import Header from '@/components/Header';
import FaturaForm from '@/components/FaturaForm';
import { useFaturas, FaturaFormData } from '@/hooks/useFaturas';


export default function NovaFaturaPage() {
  const router = useRouter();
  const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
  const { cadastrarFatura, loading } = useFaturas();

  useEffect(() => {
    account
      .get()
      .then(setUser)
      .catch(() => router.push('/'));
  }, [router]);

  const handleSubmit = async (data: FaturaFormData) => {
    const success = await cadastrarFatura(data);
    if (success) router.push('/modules/faturas');
    return success;
  };

  if (!user) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4" />
          <p className="text-gray-600">Verificando autenticação...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <Header user={user} title="Nova Fatura" subtitle="Cadastrar nova fatura" />
      <main className="max-w-2xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        <FaturaForm onSubmit={handleSubmit} loading={loading} />
      </main>
    </div>
  );
}


src/modules/faturas/types.ts

export type { FaturaData } from '@/services/faturaService';


src/services/carrinhoService.ts


const API_BASE_URL = '';

export interface CarrinhoData {
  usuarios: string;
  itens: string[];
  quantidade: number[];
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  error?: string;
  details?: any;
}

export interface PaginatedResponse<T> extends ApiResponse<T> {
  documents: T[];
  total: number;
}

class CarrinhoService {
  private async makeRequest<T>(endpoint: string, options: RequestInit = {}): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });

      const data = await response.json();
      return data;
    } catch (error) {
      return {
        success: false,
        error: 'Erro de conexão com o servidor'
      };
    }
  }

  async listar(page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const query = `?limit=${limit}&page=${page}`;
      const data = await this.makeRequest(`/api/carrinhos${query}`) as PaginatedResponse<any>;
      if (data.success) {
        return {
          success: true,
          documents: data.documents || [],
          total: data.total || 0
        };
      }
      return {
        success: false,
        error: data.error || 'Erro ao carregar carrinhos',
        documents: [],
        total: 0
      };
    } catch (error) {
      console.error('Erro ao listar carrinhos via API:', error);
      return { success: false, error: 'Erro ao carregar carrinhos', documents: [], total: 0 };
    }
  }

  async buscarPorUsuario(
    usuario: string,
    page = 1,
    limit = 10
  ): Promise<PaginatedResponse<any>> {
    try {
      const query = `?termoBuscado=${encodeURIComponent(usuario)}&limit=${limit}&page=${page}`;
      const data = await this.makeRequest(`/api/carrinhos${query}`) as PaginatedResponse<any>;
      if (data.success) {
        return {
          success: true,
          documents: data.documents || [],
          total: data.total || 0
        };
      }
      return {
        success: false,
        error: data.error || 'Erro ao buscar carrinhos',
        documents: [],
        total: 0
      };
    } catch (error) {
      console.error('Erro ao buscar carrinhos via API:', error);
      return { success: false, error: 'Erro ao buscar carrinhos', documents: [], total: 0 };
    }
  }

  async criar(data: CarrinhoData): Promise<ApiResponse> {
    return this.makeRequest('/api/carrinhos', {
      method: 'POST',
      body: JSON.stringify({
        documentId: 'unique()',
        data
      })
    });
  }

  async atualizar(id: string, data: CarrinhoData): Promise<ApiResponse> {
    return this.makeRequest(`/api/carrinhos/${id}`, {
      method: 'PATCH',
      body: JSON.stringify({ data })
    });
  }

  async deletar(id: string): Promise<ApiResponse> {
    return this.makeRequest(`/api/carrinhos/${id}`, {
      method: 'DELETE'
    });
  }
}

export const carrinhoService = new CarrinhoService();


src/services/catalogoProdutoService.ts


const API_BASE_URL = ''; // Para usar rotas relativas da API do Next.js

export interface CatalogoProdutoData {
  nome: string;
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  error?: string;
  details?: any;
}

export interface PaginatedResponse<T> extends ApiResponse<T> {
  documents: T[];
  total: number;
}

class CatalogoProdutoService {
  private async makeRequest<T>(
    endpoint: string, 
    options: RequestInit = {}
  ): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });

      const data = await response.json();
      return data;
    } catch (error) {
      return {
        success: false,
        error: 'Erro de conexão com o servidor'
      };
    }
  }

  // Método de listagem via API
  async listar(page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const query = `?limit=${limit}&page=${page}`;
      const data = (await this.makeRequest(
        `/api/catalogo-produtos${query}`
      )) as PaginatedResponse<any>;

      if (data.success) {
        return {
          success: true,
          documents: data.documents || [],
          total: data.total || 0
        };
      }

      return {
        success: false,
        error: data.error || 'Erro ao carregar catálogos de produtos',
        documents: [],
        total: 0
      };
    } catch (error) {
      console.error('Erro ao listar catálogos de produtos via API:', error);
      return {
        success: false,
        error: 'Erro ao carregar catálogos de produtos',
        documents: [],
        total: 0
      };
    }
  }

  // Buscar catálogos de produtos via API
  async buscarPorNome(
    nome: string,
    page = 1,
    limit = 10
  ): Promise<PaginatedResponse<any>> {
    try {
      const query = `?termoBuscado=${encodeURIComponent(nome)}&limit=${limit}&page=${page}`;
      const data = (await this.makeRequest(
        `/api/catalogo-produtos${query}`
      )) as PaginatedResponse<any>;

      if (data.success) {
        return {
          success: true,
          documents: data.documents || [],
          total: data.total || 0
        };
      }

      return {
        success: false,
        error: data.error || 'Erro ao buscar catálogos de produtos',
        documents: [],
        total: 0
      };
    } catch (error) {
      console.error('Erro ao buscar catálogos de produtos via API:', error);
      return {
        success: false,
        error: 'Erro ao buscar catálogos de produtos',
        documents: [],
        total: 0
      };
    }
  }

  // Métodos de criação, atualização e exclusão continuam usando API REST
  async criar(data: CatalogoProdutoData): Promise<ApiResponse> {
    return this.makeRequest('/api/catalogo-produtos', {
      method: 'POST',
      body: JSON.stringify({
        documentId: 'unique()',
        data
      })
    });
  }

  async atualizar(id: string, data: CatalogoProdutoData): Promise<ApiResponse> {
    return this.makeRequest(`/api/catalogo-produtos/${id}`, {
      method: 'PATCH',
      body: JSON.stringify({ data })
    });
  }

  async deletar(id: string): Promise<ApiResponse> {
    return this.makeRequest(`/api/catalogo-produtos/${id}`, {
      method: 'DELETE'
    });
  }
}

export const catalogoProdutoService = new CatalogoProdutoService();


src/services/categoriaService.ts

const API_BASE_URL = ''; // Para usar rotas relativas da API do Next.js

export interface CategoriaData {
  nome: string;
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  error?: string;
  details?: any;
}

export interface PaginatedResponse<T> extends ApiResponse<T> {
  documents: T[];
  total: number;
}

class CategoriaService {
  private async makeRequest<T>(
    endpoint: string, 
    options: RequestInit = {}
  ): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });

      const data = await response.json();
      return data;
    } catch (error) {
      return {
        success: false,
        error: 'Erro de conexão com o servidor'
      };
    }
  }

  // Método de listagem via API
  async listar(page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const query = `?limit=${limit}&page=${page}`;
      const data = (await this.makeRequest(`/api/categorias${query}`)) as PaginatedResponse<any>;
      if (data.success) {
        return {
          success: true,
          documents: data.documents || [],
          total: data.total || 0
        };
      }
      return {
        success: false,
        error: data.error || 'Erro ao carregar categorias',
        documents: [],
        total: 0
      };
    } catch (error) {
      console.error('Erro ao listar categorias via API:', error);
      return { success: false, error: 'Erro ao carregar categorias', documents: [], total: 0 };
    }
  }

  // Buscar categorias por nome via API
  async buscarPorNome(
    nome: string,
    page = 1,
    limit = 10
  ): Promise<PaginatedResponse<any>> {
    try {
      const query = `?termoBuscado=${encodeURIComponent(nome)}&limit=${limit}&page=${page}`;
      const data = (await this.makeRequest(`/api/categorias${query}`)) as PaginatedResponse<any>;
      if (data.success) {
        return {
          success: true,
          documents: data.documents || [],
          total: data.total || 0
        };
      }
      return {
        success: false,
        error: data.error || 'Erro ao buscar categorias',
        documents: [],
        total: 0
      };
    } catch (error) {
      console.error('Erro ao buscar categorias via API:', error);
      return { success: false, error: 'Erro ao buscar categorias', documents: [], total: 0 };
    }
  }

  // Métodos de criação, atualização e exclusão continuam usando API REST
  async criar(data: CategoriaData): Promise<ApiResponse> {
    return this.makeRequest('/api/categorias', {
      method: 'POST',
      body: JSON.stringify({
        documentId: 'unique()',
        data
      })
    });
  }

  async atualizar(id: string, data: CategoriaData): Promise<ApiResponse> {
    return this.makeRequest(`/api/categorias/${id}`, {
      method: 'PATCH',
      body: JSON.stringify({ data })
    });
  }

  async deletar(id: string): Promise<ApiResponse> {
    return this.makeRequest(`/api/categorias/${id}`, {
      method: 'DELETE'
    });
  }
}

export const categoriaService = new CategoriaService();

src/services/empresaService.ts

import { databases } from '@/lib/appwrite';
import { Query } from 'appwrite';

const API_BASE_URL = '';

export interface EmpresaData {
  cnpj: string;
  'razao-social': string;
  'nome-fantasia': string;
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  error?: string;
  details?: any;
}

export interface PaginatedResponse<T> extends ApiResponse<T> {
  documents: T[];
  total: number;
}

class EmpresaService {
  private async makeRequest<T>(endpoint: string, options: RequestInit = {}): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });

      const data = await response.json();
      return data;
    } catch (error) {
      return {
        success: false,
        error: 'Erro de conexão com o servidor'
      };
    }
  }

  // Listagem via SDK do Appwrite
  async listar(page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_EMPRESAS_ID!;

      const offset = (page - 1) * limit;

      const response = await databases.listDocuments(
        databaseId,
        collectionId,
        [
          Query.limit(limit),
          Query.offset(offset)
        ]
      );

      return {
        success: true,
        documents: response.documents,
        total: response.total
      };
    } catch (error) {
      console.error('Erro ao listar empresas via SDK:', error);
      return {
        success: false,
        error: 'Erro ao carregar empresas',
        documents: [],
        total: 0
      };
    }
  }

  async criar(data: EmpresaData): Promise<ApiResponse> {
    return this.makeRequest('/api/empresas', {
      method: 'POST',
      body: JSON.stringify({
        documentId: 'unique()',
        data
      })
    });
  }

  async atualizar(id: string, data: EmpresaData): Promise<ApiResponse> {
    return this.makeRequest(`/api/empresas/${id}`, {
      method: 'PATCH',
      body: JSON.stringify({ data })
    });
  }

  async deletar(id: string): Promise<ApiResponse> {
    return this.makeRequest(`/api/empresas/${id}`, {
      method: 'DELETE'
    });
  }
}

export const empresaService = new EmpresaService();


src/services/enderecoService.ts

import { databases } from '@/lib/appwrite';
import { Query } from 'appwrite';

const API_BASE_URL = '';

export interface EnderecoData {
  titulo: string;
  cep: string;
  logradouro: string;
  bairro: string;
  numero: string;
  complemento: string;
  cidade: string;
  estado: string;
  pais: string;
  latitude: number;
  longitude: number;
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  error?: string;
  details?: any;
}

export interface PaginatedResponse<T> extends ApiResponse<T> {
  documents: T[];
  total: number;
}

class EnderecoService {
  private async makeRequest<T>(endpoint: string, options: RequestInit = {}): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });

      const data = await response.json();
      return data;
    } catch (error) {
      return {
        success: false,
        error: 'Erro de conexão com o servidor'
      };
    }
  }

  async listar(page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_ENDERECOS_ID!;

      const offset = (page - 1) * limit;

      const response = await databases.listDocuments(
        databaseId,
        collectionId,
        [
          Query.limit(limit),
          Query.offset(offset)
        ]
      );

      return {
        success: true,
        documents: response.documents,
        total: response.total
      };
    } catch (error) {
      console.error('Erro ao listar endereços via SDK:', error);
      return {
        success: false,
        error: 'Erro ao carregar endereços',
        documents: [],
        total: 0
      };
    }
  }

  async buscar(termo: string, page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_ENDERECOS_ID!;

      const offset = (page - 1) * limit;

      const response = await databases.listDocuments(databaseId, collectionId, [
        Query.or([
          Query.search('titulo', termo),
          Query.search('cep', termo),
          Query.search('cidade', termo)
        ]),
        Query.limit(limit),
        Query.offset(offset)
      ]);

      return {
        success: true,
        documents: response.documents,
        total: response.total
      };
    } catch (error) {
      console.error('Erro ao buscar endereços via SDK:', error);
      return {
        success: false,
        error: 'Erro ao buscar endereços',
        documents: [],
        total: 0
      };
    }
  }

  async criar(data: EnderecoData): Promise<ApiResponse> {
    return this.makeRequest('/api/enderecos', {
      method: 'POST',
      body: JSON.stringify({
        documentId: 'unique()',
        data
      })
    });
  }

  async atualizar(id: string, data: EnderecoData): Promise<ApiResponse> {
    return this.makeRequest(`/api/enderecos/${id}`, {
      method: 'PATCH',
      body: JSON.stringify({ data })
    });
  }

  async deletar(id: string): Promise<ApiResponse> {
    return this.makeRequest(`/api/enderecos/${id}`, {
      method: 'DELETE'
    });
  }
}

export const enderecoService = new EnderecoService();


src/services/faturaService.ts

import { databases } from '@/lib/appwrite';
import { Query } from 'appwrite';

const API_BASE_URL = ''; // Para usar rotas relativas da API do Next.js

export interface FaturaData {
  nome: string;
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  error?: string;
  details?: any;
}

export interface PaginatedResponse<T> extends ApiResponse<T> {
  documents: T[];
  total: number;
}

class FaturaService {
  private async makeRequest<T>(
    endpoint: string, 
    options: RequestInit = {}
  ): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });

      const data = await response.json();
      return data;
    } catch (error) {
      return {
        success: false,
        error: 'Erro de conexão com o servidor'
      };
    }
  }

  // Método de listagem usando SDK do Appwrite
  async listar(page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_FATURAS_ID!;
      
      const offset = (page - 1) * limit;
      
      const response = await databases.listDocuments(
        databaseId,
        collectionId,
        [
          Query.limit(limit),
          Query.offset(offset)
        ]
      );

      return {
        success: true,
        documents: response.documents,
        total: response.total
      };
    } catch (error) {
      console.error('Erro ao listar faturas via SDK:', error);
      return {
        success: false,
        error: 'Erro ao carregar faturas',
        documents: [],
        total: 0
      };
    }
  }

  // Buscar faturas por nome usando SDK do Appwrite
  async buscarPorNome(
    nome: string,
    page = 1,
    limit = 10
  ): Promise<PaginatedResponse<any>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId =
        process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_FATURAS_ID!;

      const offset = (page - 1) * limit;

      const response = await databases.listDocuments(databaseId, collectionId, [
        Query.search('nome', nome),
        Query.limit(limit),
        Query.offset(offset)
      ]);

      return {
        success: true,
        documents: response.documents,
        total: response.total
      };
    } catch (error) {
      console.error('Erro ao buscar faturas via SDK:', error);
      return {
        success: false,
        error: 'Erro ao buscar faturas',
        documents: [],
        total: 0
      };
    }
  }

  // Métodos de criação, atualização e exclusão continuam usando API REST
  async criar(data: FaturaData): Promise<ApiResponse> {
    return this.makeRequest('/api/faturas', {
      method: 'POST',
      body: JSON.stringify({
        documentId: 'unique()',
        data
      })
    });
  }

  async atualizar(id: string, data: FaturaData): Promise<ApiResponse> {
    return this.makeRequest(`/api/faturas/${id}`, {
      method: 'PATCH',
      body: JSON.stringify({ data })
    });
  }

  async deletar(id: string): Promise<ApiResponse> {
    return this.makeRequest(`/api/faturas/${id}`, {
      method: 'DELETE'
    });
  }

  async obterPorId(id: string): Promise<ApiResponse<any>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_FATURAS_ID!;
      
      const response = await databases.getDocument(
        databaseId,
        collectionId,
        id
      );

      return {
        success: true,
        data: response
      };
    } catch (error) {
      console.error('Erro ao obter fatura via SDK:', error);
      return {
        success: false,
        error: 'Erro ao carregar fatura'
      };
    }
  }
}

export const faturaService = new FaturaService();


src/services/laboratorioService.ts

import { databases } from '@/lib/appwrite';
import { Query } from 'appwrite';

const API_BASE_URL = ''; // Para usar rotas relativas da API do Next.js

export interface LaboratorioData {
  nome: string;
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  error?: string;
  details?: any;
}

export interface PaginatedResponse<T> extends ApiResponse<T> {
  documents: T[];
  total: number;
}

class LaboratorioService {
  private async makeRequest<T>(
    endpoint: string, 
    options: RequestInit = {}
  ): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });

      const data = await response.json();
      return data;
    } catch (error) {
      return {
        success: false,
        error: 'Erro de conexão com o servidor'
      };
    }
  }

  // Método de listagem usando SDK do Appwrite
  async listar(page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_LABORATORIOS_ID!;
      
      const offset = (page - 1) * limit;
      
      const response = await databases.listDocuments(
        databaseId,
        collectionId,
        [
          Query.limit(limit),
          Query.offset(offset)
        ]
      );

      return {
        success: true,
        documents: response.documents,
        total: response.total
      };
    } catch (error) {
      console.error('Erro ao listar laboratórios via SDK:', error);
      return {
        success: false,
        error: 'Erro ao carregar laboratórios',
        documents: [],
        total: 0
      };
    }
  }

  // Buscar laboratórios por nome usando SDK do Appwrite
  async buscarPorNome(
    nome: string,
    page = 1,
    limit = 10
  ): Promise<PaginatedResponse<any>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId =
        process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_LABORATORIOS_ID!;

      const offset = (page - 1) * limit;

      const response = await databases.listDocuments(databaseId, collectionId, [
        Query.search('nome', nome),
        Query.limit(limit),
        Query.offset(offset)
      ]);

      return {
        success: true,
        documents: response.documents,
        total: response.total
      };
    } catch (error) {
      console.error('Erro ao buscar laboratórios via SDK:', error);
      return {
        success: false,
        error: 'Erro ao buscar laboratórios',
        documents: [],
        total: 0
      };
    }
  }

  // Métodos de criação, atualização e exclusão continuam usando API REST
  async criar(data: LaboratorioData): Promise<ApiResponse> {
    return this.makeRequest('/api/laboratorios', {
      method: 'POST',
      body: JSON.stringify({
        documentId: 'unique()',
        data
      })
    });
  }

  async atualizar(id: string, data: LaboratorioData): Promise<ApiResponse> {
    return this.makeRequest(`/api/laboratorios/${id}`, {
      method: 'PATCH',
      body: JSON.stringify({ data })
    });
  }

  async deletar(id: string): Promise<ApiResponse> {
    return this.makeRequest(`/api/laboratorios/${id}`, {
      method: 'DELETE'
    });
  }
}

export const laboratorioService = new LaboratorioService();

src/services/pagamentoService.ts

import { databases } from '@/lib/appwrite';
import { Query } from 'appwrite';

const API_BASE_URL = '';

export interface PagamentoData {
  pedidos: string;
  status: string;
  metodo: string;
  valor: number;
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  error?: string;
  details?: any;
}

export interface PaginatedResponse<T> extends ApiResponse<T> {
  documents: T[];
  total: number;
}

class PagamentoService {
  private async makeRequest<T>(endpoint: string, options: RequestInit = {}): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });

      const data = await response.json();
      return data;
    } catch (error) {
      return {
        success: false,
        error: 'Erro de conexão com o servidor'
      };
    }
  }

  async listar(
    page = 1,
    limit = 10,
    search = ''
  ): Promise<PaginatedResponse<PagamentoData>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PAGAMENTOS_ID!;

      const offset = (page - 1) * limit;

      const queries = [Query.limit(limit), Query.offset(offset)];
      if (search) {
        queries.push(Query.search('status', search));
      }

      const response = await databases.listDocuments(
        databaseId,
        collectionId,
        queries
      );

      return {
        success: true,
        documents: response.documents as unknown as PagamentoData[],
        total: response.total
      };
    } catch (error) {
      console.error('Erro ao listar pagamentos via SDK:', error);
      return {
        success: false,
        error: 'Erro ao carregar pagamentos',
        documents: [],
        total: 0
      };
    }
  }

  async criar(data: PagamentoData): Promise<ApiResponse> {
    return this.makeRequest('/api/pagamentos', {
      method: 'POST',
      body: JSON.stringify({
        documentId: 'unique()',
        data
      })
    });
  }

  async atualizar(id: string, data: PagamentoData): Promise<ApiResponse> {
    return this.makeRequest(`/api/pagamentos/${id}`, {
      method: 'PUT',
      body: JSON.stringify({ data })
    });
  }

  async deletar(id: string): Promise<ApiResponse> {
    return this.makeRequest(`/api/pagamentos/${id}`, {
      method: 'DELETE'
    });
  }
}

export const pagamentoService = new PagamentoService();


src/services/pedidoService.ts

import { databases } from '@/lib/appwrite';
import { Query } from 'appwrite';

const API_BASE_URL = '';

export interface PedidoData {
  status: string;
  'valor-total': number;
  itens: string[];
  comprador: string;
  vendedor: string;
Última atualização: 2025-07-15

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  error?: string;
  details?: any;
}

export interface PaginatedResponse<T> extends ApiResponse<T> {
  documents: T[];
  total: number;
}

class PedidoService {
  private async makeRequest<T>(endpoint: string, options: RequestInit = {}): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });
      const data = await response.json();
      return data;
    } catch (error) {
      return { success: false, error: 'Erro de conexão com o servidor' };
    }
  }

  async listar(page = 1, limit = 10, status = '', search = ''): Promise<PaginatedResponse<any>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PEDIDOS_ID!;
      const offset = (page - 1) * limit;

      const queries = [Query.limit(limit), Query.offset(offset)];
      if (status) queries.push(Query.equal('status', status));
      if (search) queries.push(Query.search('comprador', search));

      const response = await databases.listDocuments(databaseId, collectionId, queries);

      return {
        success: true,
        documents: response.documents,
        total: response.total,
      };
    } catch (error) {
      console.error('Erro ao listar pedidos via SDK:', error);
      return { success: false, error: 'Erro ao carregar pedidos', documents: [], total: 0 };
    }
  }

  async criar(data: PedidoData): Promise<ApiResponse> {
    return this.makeRequest('/api/pedidos', {
      method: 'POST',
      body: JSON.stringify({ documentId: 'unique()', data }),
    });
  }

  async atualizar(id: string, data: PedidoData): Promise<ApiResponse> {
    return this.makeRequest(`/api/pedidos/${id}`, {
      method: 'PATCH',
      body: JSON.stringify({ data }),
    });
  }

  async deletar(id: string): Promise<ApiResponse> {

### src/components/CatalogoProdutosSearch.tsx
```tsx
import React, { useState, useEffect } from 'react';

interface Props {
  onSearch: (params: { termo: string; filtros: any }) => void;
}

const CatalogoProdutosSearch: React.FC<Props> = ({ onSearch }) => {
  const [searchTerm, setSearchTerm] = useState('');
  const [filters, setFilters] = useState({
    categoria: '',
    laboratorio: '',
    temPreco: false,
    ordenacao: 'descricao'
  });

  useEffect(() => {
    const handler = setTimeout(() => {
      onSearch({ termo: searchTerm, filtros: filters });
    }, 500);
    return () => clearTimeout(handler);
  }, [searchTerm, filters, onSearch]);

  const handleSearchClick = () => {
    onSearch({ termo: searchTerm, filtros: filters });
  };

  return (
    <div className="bg-white p-4 rounded-lg shadow mb-6">
      <div className="grid grid-cols-1 md:grid-cols-4 gap-4 mb-4">
        <div className="md:col-span-2">
          <label className="block text-sm font-medium text-gray-700 mb-1" htmlFor="busca">
            Buscar produto
          </label>
          <input
            id="busca"
            type="text"
            value={searchTerm}
            onChange={e => setSearchTerm(e.target.value)}
            onKeyPress={e => e.key === 'Enter' && handleSearchClick()}
            placeholder="Nome, código interno, EAN ou laboratório"
            aria-label="Buscar produto"
            className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
          />
        </div>
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1" htmlFor="categoria">
            Categoria
          </label>
          <select
            id="categoria"
            value={filters.categoria}
            onChange={e => setFilters({ ...filters, categoria: e.target.value })}
            className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
          >
            <option value="">Todas</option>
            <option value="OTC">OTC</option>
            <option value="Dermo">Dermo</option>
            <option value="HB">HB</option>
            <option value="RX">RX</option>
            <option value="Genérico">Genérico</option>
          </select>
        </div>
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1" htmlFor="ordenacao">
            Ordenar por
          </label>
          <select
            id="ordenacao"
            value={filters.ordenacao}
            onChange={e => setFilters({ ...filters, ordenacao: e.target.value })}
            className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
          >
            <option value="descricao">Nome do produto</option>
            <option value="codigo-interno">Código interno</option>
            <option value="categoria">Categoria</option>
            <option value="laboratorio">Laboratório</option>
          </select>
        </div>
      </div>
      <div className="flex items-center space-x-4">
        <label className="flex items-center">
          <input
            type="checkbox"
            checked={filters.temPreco}
            onChange={e => setFilters({ ...filters, temPreco: e.target.checked })}
            className="mr-2"
          />
          <span className="text-sm text-gray-700">Apenas com preços</span>
        </label>
        <button
          onClick={handleSearchClick}
          className="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500"
        >
          Buscar
        </button>
        <button
          onClick={() => {
            setSearchTerm('');
            setFilters({ categoria: '', laboratorio: '', temPreco: false, ordenacao: 'descricao' });
            onSearch({ termo: '', filtros: {} });
          }}
          className="bg-gray-500 text-white px-4 py-2 rounded-md hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500"
        >
          Limpar
        </button>
      </div>
    </div>
  );
};

export default CatalogoProdutosSearch;

src/components/StandardButton.tsx

import React from 'react';

interface StandardButtonProps {
  onClick: () => void;
  children: React.ReactNode;
  variant?: 'primary' | 'secondary';
  disabled?: boolean;
  className?: string;
}

const StandardButton: React.FC<StandardButtonProps> = ({
  onClick,
  children,
  variant = 'primary',
  disabled = false,
  className = ''
}) => {
  const baseClasses =
    'h-10 px-6 rounded-md font-medium text-sm transition-colors duration-200 flex items-center space-x-2';

  const variantClasses = {
    primary:
      'bg-blue-600 text-white hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2',
    secondary:
      'bg-gray-500 text-white hover:bg-gray-600 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2'
  } as const;

  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className={`${baseClasses} ${variantClasses[variant]} ${disabled ? 'opacity-50 cursor-not-allowed' : ''} ${className}`}
    >
      {children}
    </button>
  );
};

export default StandardButton;

src/components/TableContainer.tsx

import React from 'react';

interface TableContainerProps {
  title: string;
  children: React.ReactNode;
  buttons?: React.ReactNode;
  className?: string;
}

const TableContainer: React.FC<TableContainerProps> = ({
  title,
  children,
  buttons,
  className = ''
}) => {
  return (
    <div className={`container mx-auto px-4 py-8 ${className}`}> 
      {/* Header Card - Mesmo tamanho da tabela */}
      <div className="bg-white rounded-lg shadow-md mb-6">
        <div className="px-6 py-4 border-b border-gray-200">
          <div className="flex items-center justify-between">
            <h1 className="text-xl font-semibold text-gray-900">{title}</h1>
            {buttons && <div className="flex space-x-2">{buttons}</div>}
          </div>
        </div>
      </div>

      {/* Content Card - Mesmo tamanho da tabela */}
      <div className="bg-white rounded-lg shadow-md overflow-hidden">
        {children}
      </div>
    </div>
  );
};

export default TableContainer;

Última atualização: 2025-07-14 return this.makeRequest(/api/pedidos/${id}, { method: 'DELETE' }); } }

export const pedidoService = new PedidoService();


---

### src/services/produtoService.ts
```typescript

const API_BASE_URL = '';

export interface ProdutoData {
  nome: string;
  'preco-original': number;
  'preco-atual': number;
  'catalogo-produto-id': string;
  'empresa-id': string;
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  error?: string;
  details?: any;
}

export interface PaginatedResponse<T> extends ApiResponse<T> {

Última atualização: 2025-07-15
  documents: T[];
  total: number;
}

class ProdutoService {
  private async makeRequest<T>(endpoint: string, options: RequestInit = {}): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...(options.headers || {})
        },
        ...options
      });

      const data = await response.json();
      return data;
    } catch (error) {
      return { success: false, error: 'Erro de conexão com o servidor' };
    }
  }

  async listar(page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const query = `?limit=${limit}&page=${page}`;
      const data = await this.makeRequest(`/api/produtos${query}`) as PaginatedResponse<ProdutoData>;
      if (data.success) {
        return {
          success: true,
          documents: data.documents || [],
          total: data.total || 0
        };
      }
      return {
        success: false,
        error: data.error || 'Erro ao carregar produtos',
        documents: [],
        total: 0
      };
    } catch (error) {
      console.error('Erro ao listar produtos via API:', error);
      return { success: false, error: 'Erro ao carregar produtos', documents: [], total: 0 };
    }
  }

  async buscarPorNome(nome: string, page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const query = `?termoBuscado=${encodeURIComponent(nome)}&limit=${limit}&page=${page}`;
      const data = await this.makeRequest(`/api/produtos${query}`) as PaginatedResponse<ProdutoData>;
      if (data.success) {
        return {
          success: true,
          documents: data.documents || [],
          total: data.total || 0
        };
      }
      return {
        success: false,
        error: data.error || 'Erro ao buscar produtos',
        documents: [],
        total: 0
      };
    } catch (error) {
      console.error('Erro ao buscar produtos via API:', error);
      return { success: false, error: 'Erro ao buscar produtos', documents: [], total: 0 };
    }
  }

  async criar(data: ProdutoData): Promise<ApiResponse> {
    return this.makeRequest('/api/produtos', {
      method: 'POST',
      body: JSON.stringify({ documentId: 'unique()', data })
    });
  }

  async atualizar(id: string, data: ProdutoData): Promise<ApiResponse> {
    return this.makeRequest(`/api/produtos/${id}`, {
      method: 'PATCH',
      body: JSON.stringify({ data })
    });
  }

  async deletar(id: string): Promise<ApiResponse> {
    return this.makeRequest(`/api/produtos/${id}`, { method: 'DELETE' });
  }
}

export const produtoService = new ProdutoService();


src/services/usuarioService.ts

import { databases } from '@/lib/appwrite';
import { Query } from 'appwrite';

const API_BASE_URL = '';

export interface UsuarioData {
  'nome-civil': string;
  'nome-social': string;
  cpf: string;
  'auth-id-appwrite': string;
  enderecos: string;
  empresas: string;
  email: string;
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  error?: string;
  details?: any;
}

export interface PaginatedResponse<T> extends ApiResponse<T> {
  documents: T[];
  total: number;
}

class UsuarioService {
  private async makeRequest<T>(
    endpoint: string,
    options: RequestInit = {}
  ): Promise<ApiResponse<T>> {
    try {
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });

      const data = await response.json();
      return data;
    } catch (error) {
      return {
        success: false,
        error: 'Erro de conexão com o servidor',
      };
    }
  }

  async listar(page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_USUARIOS_ID!;

      const offset = (page - 1) * limit;

      const response = await databases.listDocuments(databaseId, collectionId, [
        Query.limit(limit),
        Query.offset(offset),
      ]);

      return {
        success: true,
        documents: response.documents,
        total: response.total,
      };
    } catch (error) {
      console.error('Erro ao listar usuários via SDK:', error);
      return {
        success: false,
        error: 'Erro ao carregar usuários',
        documents: [],
        total: 0,
      };
    }
  }

  async buscarPorNome(nome: string, page = 1, limit = 10): Promise<PaginatedResponse<any>> {
    try {
      const databaseId = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID!;
      const collectionId = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_USUARIOS_ID!;

      const offset = (page - 1) * limit;

      const response = await databases.listDocuments(databaseId, collectionId, [
        Query.or([
          Query.search('nome-civil', nome),
          Query.search('email', nome)
        ]),
        Query.limit(limit),
        Query.offset(offset),
      ]);

      return {
        success: true,
        documents: response.documents,
        total: response.total,
      };
    } catch (error) {
      console.error('Erro ao buscar usuários via SDK:', error);
      return {
        success: false,
        error: 'Erro ao buscar usuários',
        documents: [],
        total: 0,
      };
    }
  }

  async criar(data: UsuarioData): Promise<ApiResponse> {
    return this.makeRequest('/api/usuarios', {
      method: 'POST',
      body: JSON.stringify({
        documentId: 'unique()',
        data,
      }),
    });
  }

  async atualizar(id: string, data: UsuarioData): Promise<ApiResponse> {
    return this.makeRequest(`/api/usuarios/${id}`, {
      method: 'PATCH',
      body: JSON.stringify({ data }),
    });
  }

  async deletar(id: string): Promise<ApiResponse> {
    return this.makeRequest(`/api/usuarios/${id}`, {
      method: 'DELETE',
    });
  }
}

export const usuarioService = new UsuarioService();


tsconfig.json

{
  "compilerOptions": {
    "target": "ES2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}