From 7e17a9847b578253effcab640bc2b9119782d7aa Mon Sep 17 00:00:00 2001 From: M-Gabrielly Date: Mon, 27 Oct 2025 23:54:36 -0300 Subject: [PATCH] feat(dashboard): add dashboard --- susconecta/Documentação API.md | 2565 ----------------- .../app/(main-routes)/dashboard/page.tsx | 432 ++- susconecta/lib/api.ts | 203 ++ 3 files changed, 600 insertions(+), 2600 deletions(-) delete mode 100644 susconecta/Documentação API.md diff --git a/susconecta/Documentação API.md b/susconecta/Documentação API.md deleted file mode 100644 index b1b9604..0000000 --- a/susconecta/Documentação API.md +++ /dev/null @@ -1,2565 +0,0 @@ -# Listar atribuições de pacientes - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /rest/v1/patient_assignments: - get: - summary: Listar atribuições de pacientes - deprecated: false - description: '' - tags: - - Atribuições - - Atribuições - parameters: - - name: apikey - in: header - description: Chave da API Supabase - required: true - example: '' - schema: - type: string - responses: - '200': - description: Lista de atribuições - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/PatientAssignment' - headers: {} - x-apidog-name: OK - security: - - bearer: [] - x-apidog-folder: Atribuições - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940525-run -components: - schemas: - PatientAssignment: - type: object - properties: - id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - patient_id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - user_id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - role: - type: string - enum: - - medico - - enfermeiro - examples: - - medico - created_at: - type: string - format: date-time - examples: - - '2024-01-15T10:30:00Z' - created_by: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - x-apidog-orders: - - id - - patient_id - - user_id - - role - - created_at - - created_by - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Criar nova atribuição - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /rest/v1/patient_assignments: - post: - summary: Criar nova atribuição - deprecated: false - description: '' - tags: - - Atribuições - - Atribuições - parameters: - - name: apikey - in: header - description: Chave da API Supabase - required: true - example: '' - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/PatientAssignmentInput' - responses: - '201': - description: Atribuição criada - content: - application/json: - schema: - $ref: '#/components/schemas/PatientAssignment' - headers: {} - x-apidog-name: Created - security: - - bearer: [] - x-apidog-folder: Atribuições - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940526-run -components: - schemas: - PatientAssignmentInput: - type: object - required: - - patient_id - - user_id - - role - properties: - patient_id: - type: string - format: uuid - user_id: - type: string - format: uuid - role: - type: string - enum: - - medico - - enfermeiro - x-apidog-orders: - - patient_id - - user_id - - role - x-apidog-ignore-properties: [] - x-apidog-folder: '' - PatientAssignment: - type: object - properties: - id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - patient_id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - user_id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - role: - type: string - enum: - - medico - - enfermeiro - examples: - - medico - created_at: - type: string - format: date-time - examples: - - '2024-01-15T10:30:00Z' - created_by: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - x-apidog-orders: - - id - - patient_id - - user_id - - role - - created_at - - created_by - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Listar roles de usuários - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /rest/v1/user_roles: - get: - summary: Listar roles de usuários - deprecated: false - description: '' - tags: - - Usuários - - Usuários - parameters: [] - responses: - '200': - description: Lista de roles - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/UserRole' - headers: {} - x-apidog-name: OK - security: - - bearer: [] - x-apidog-folder: Usuários - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940524-run -components: - schemas: - UserRole: - type: object - properties: - id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - user_id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - role: - type: string - enum: - - admin - - gestor - - medico - examples: - - medico - created_at: - type: string - format: date-time - examples: - - '2024-01-15T10:30:00Z' - x-apidog-orders: - - id - - user_id - - role - - created_at - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Obter informações completas do usuário - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /functions/v1/user-info: - get: - summary: Obter informações completas do usuário - deprecated: false - description: >- - Retorna dados consolidados do usuário autenticado, incluindo perfil e - roles para controle de permissões. - tags: - - Usuários - parameters: [] - responses: - '200': - description: Informações do usuário retornadas com sucesso - content: - application/json: - schema: - $ref: '#/components/schemas/UserInfoResponse' - headers: {} - x-apidog-name: OK - '401': - description: Token inválido ou expirado - content: - application/json: - schema: &ref_0 - $ref: '#/components/schemas/Error' - headers: {} - x-apidog-name: Unauthorized - '500': - description: Erro interno do servidor - content: - application/json: - schema: *ref_0 - headers: {} - x-apidog-name: Internal Server Error - security: [] - x-apidog-folder: Usuários - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21952675-run -components: - schemas: - UserInfoResponse: - type: object - properties: - user: - $ref: '#/components/schemas/User' - profile: - $ref: '#/components/schemas/Profile' - roles: - type: array - items: - type: string - enum: - - admin - - gestor - - medico - - secretaria - - user - examples: - - - medico - - admin - permissions: - $ref: '#/components/schemas/Permissions' - x-apidog-orders: - - user - - profile - - roles - - permissions - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Permissions: - type: object - properties: - isAdmin: - type: boolean - description: Se o usuário tem role de admin - examples: - - true - isManager: - type: boolean - description: Se o usuário tem role de gestor - examples: - - false - isDoctor: - type: boolean - description: Se o usuário tem role de médico - examples: - - true - isSecretary: - type: boolean - description: Se o usuário tem role de secretária - examples: - - false - isAdminOrManager: - type: boolean - description: Se o usuário é admin ou gestor (para controle de permissões) - examples: - - true - x-apidog-orders: - - isAdmin - - isManager - - isDoctor - - isSecretary - - isAdminOrManager - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Profile: - type: object - properties: - id: - type: string - format: uuid - full_name: - type: string - examples: - - Dr. João Silva - nullable: true - email: - type: string - format: email - nullable: true - phone: - type: string - examples: - - '+5511999999999' - nullable: true - avatar_url: - type: string - format: uri - nullable: true - disabled: - type: boolean - examples: - - false - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - x-apidog-orders: - - id - - full_name - - email - - phone - - avatar_url - - disabled - - created_at - - updated_at - x-apidog-ignore-properties: [] - nullable: true - x-apidog-folder: '' - User: - type: object - properties: - id: - type: string - format: uuid - examples: - - 550e8400-e29b-41d4-a716-446655440000 - email: - type: string - format: email - examples: - - usuario@exemplo.com - email_confirmed_at: - type: string - format: date-time - examples: - - '2024-01-01T10:00:00Z' - nullable: true - created_at: - type: string - format: date-time - examples: - - '2024-01-01T00:00:00Z' - last_sign_in_at: - type: string - format: date-time - examples: - - '2024-01-15T09:30:00Z' - nullable: true - x-apidog-orders: - - id - - email - - email_confirmed_at - - created_at - - last_sign_in_at - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Error: - type: object - properties: - error: - type: string - message: - type: string - code: - type: string - x-apidog-orders: - - error - - message - - code - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Criar novo usuário - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /functions/v1/create-user: - post: - summary: Criar novo usuário - deprecated: false - description: >- - Cria um novo usuário no sistema com papel específico. Apenas usuários - com papel de admin, gestor ou secretaria podem criar novos usuários. - operationId: createUser - tags: - - Usuários - - Usuários - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/CreateUserRequest' - examples: - admin_user: - value: - email: admin@mediconnect.com - password: senha123! - full_name: João Silva - phone: (11) 99999-9999 - role: admin - summary: Criar administrador - doctor_user: - value: - email: dr.maria@mediconnect.com - password: senha123! - full_name: Dra. Maria Santos - phone: (11) 98888-8888 - role: medico - summary: Criar médico - secretary_user: - value: - email: secretaria@mediconnect.com - password: senha123! - full_name: Ana Costa - phone: (11) 97777-7777 - role: secretaria - summary: Criar secretária - responses: - '200': - description: Usuário criado com sucesso - content: - application/json: - schema: - $ref: '#/components/schemas/CreateUserResponse' - example: - success: true - user: - id: 123e4567-e89b-12d3-a456-426614174000 - email: novo.usuario@mediconnect.com - full_name: Novo Usuário - phone: (11) 99999-9999 - role: medico - headers: {} - x-apidog-name: OK - '400': - description: Dados inválidos ou erro de validação - content: - application/json: - schema: - type: object - properties: {} - x-apidog-ignore-properties: [] - x-apidog-orders: [] - examples: - '2': - summary: Campos obrigatórios faltando - value: - error: 'Missing required fields: email, password, full_name, role' - '3': - summary: Papel inválido - value: - error: Invalid role - '4': - summary: Email já existe - value: - error: User with this email already registered - headers: {} - x-apidog-name: Bad Request - '401': - description: Token de autenticação inválido ou ausente - content: - application/json: - schema: - type: object - properties: {} - x-apidog-ignore-properties: [] - x-apidog-orders: [] - example: - error: Unauthorized - headers: {} - x-apidog-name: Unauthorized - '403': - description: Permissões insuficientes - content: - application/json: - schema: - type: object - properties: {} - x-apidog-ignore-properties: [] - x-apidog-orders: [] - example: - error: Insufficient permissions - headers: {} - x-apidog-name: Forbidden - '500': - description: Erro interno do servidor - content: - application/json: - schema: - type: object - properties: {} - x-apidog-ignore-properties: [] - x-apidog-orders: [] - example: - error: Internal server error - headers: {} - x-apidog-name: Internal Server Error - security: [] - x-apidog-folder: Usuários - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21953135-run -components: - schemas: - CreateUserRequest: - type: object - required: - - email - - password - - full_name - - role - properties: - email: - type: string - format: email - description: Email do usuário (deve ser único) - examples: - - usuario@mediconnect.com - password: - type: string - minLength: 6 - description: Senha temporária para o usuário - examples: - - senha123! - full_name: - type: string - minLength: 1 - description: Nome completo do usuário - examples: - - João da Silva - phone: - type: string - description: Telefone do usuário (opcional) - examples: - - (11) 99999-9999 - nullable: true - role: - type: string - enum: - - admin - - gestor - - medico - - secretaria - - user - description: Papel do usuário no sistema - examples: - - medico - x-apidog-orders: - - email - - password - - full_name - - phone - - role - x-apidog-ignore-properties: [] - x-apidog-folder: '' - CreateUserResponse: - type: object - properties: - success: - type: boolean - description: Indica se a operação foi bem-sucedida - examples: - - true - user: - type: object - properties: - id: - type: string - format: uuid - description: ID único do usuário criado - examples: - - 123e4567-e89b-12d3-a456-426614174000 - email: - type: string - format: email - description: Email do usuário - examples: - - usuario@mediconnect.com - full_name: - type: string - description: Nome completo do usuário - examples: - - João da Silva - phone: - type: string - description: Telefone do usuário - examples: - - (11) 99999-9999 - nullable: true - role: - type: string - description: Papel atribuído ao usuário - examples: - - medico - x-apidog-orders: - - id - - email - - full_name - - phone - - role - x-apidog-ignore-properties: [] - x-apidog-orders: - - success - - user - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Obter dados do usuário atual - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /auth/v1/user: - get: - summary: Obter dados do usuário atual - deprecated: false - description: Retorna informações do usuário autenticado - tags: - - Usuários - - Authentication - parameters: [] - responses: - '200': - description: Dados do usuário - content: - application/json: - schema: - $ref: '#/components/schemas/User' - headers: {} - x-apidog-name: OK - '401': - description: Token inválido - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - headers: {} - x-apidog-name: Unauthorized - security: - - bearer: [] - x-apidog-folder: Usuários - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940512-run -components: - schemas: - User: - type: object - properties: - id: - type: string - format: uuid - examples: - - 550e8400-e29b-41d4-a716-446655440000 - email: - type: string - format: email - examples: - - usuario@exemplo.com - email_confirmed_at: - type: string - format: date-time - examples: - - '2024-01-01T10:00:00Z' - nullable: true - created_at: - type: string - format: date-time - examples: - - '2024-01-01T00:00:00Z' - last_sign_in_at: - type: string - format: date-time - examples: - - '2024-01-15T09:30:00Z' - nullable: true - x-apidog-orders: - - id - - email - - email_confirmed_at - - created_at - - last_sign_in_at - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Error: - type: object - properties: - error: - type: string - message: - type: string - code: - type: string - x-apidog-orders: - - error - - message - - code - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` -# Fazer login e obter token JWT - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /auth/v1/token: - post: - summary: Fazer login e obter token JWT - deprecated: false - description: >- - Autentica o usuário e retorna um token JWT para usar em outras - requisições. - tags: - - Authentication - parameters: - - name: grant_type - in: query - description: '' - required: true - schema: - type: string - enum: - - password - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/LoginRequest' - examples: {} - responses: - '200': - description: Login realizado com sucesso - content: - application/json: - schema: - $ref: '#/components/schemas/LoginResponse' - headers: {} - x-apidog-name: OK - '400': - description: Credenciais inválidas - content: - application/json: - schema: &ref_0 - $ref: '#/components/schemas/Error' - headers: {} - x-apidog-name: Bad Request - '401': - description: Email ou senha incorretos - content: - application/json: - schema: *ref_0 - headers: {} - x-apidog-name: Unauthorized - security: - - bearer: [] - x-apidog-folder: Authentication - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940510-run -components: - schemas: - LoginRequest: - type: object - required: - - email - - password - properties: - email: - type: string - format: email - examples: - - usuario@exemplo.com - password: - type: string - minLength: 6 - examples: - - senha123 - x-apidog-orders: - - email - - password - x-apidog-ignore-properties: [] - x-apidog-folder: '' - LoginResponse: - type: object - properties: - access_token: - type: string - description: Token JWT para autenticação - examples: - - eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... - token_type: - type: string - examples: - - bearer - expires_in: - type: integer - description: Tempo de expiração do token em segundos - examples: - - 3600 - refresh_token: - type: string - description: Token para renovar o access_token - user: - $ref: '#/components/schemas/AuthUser' - x-apidog-orders: - - access_token - - token_type - - expires_in - - refresh_token - - user - x-apidog-ignore-properties: [] - x-apidog-folder: '' - AuthUser: - type: object - properties: - id: - type: string - format: uuid - email: - type: string - format: email - email_confirmed_at: - type: string - format: date-time - nullable: true - created_at: - type: string - format: date-time - x-apidog-orders: - - id - - email - - email_confirmed_at - - created_at - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Error: - type: object - properties: - error: - type: string - message: - type: string - code: - type: string - x-apidog-orders: - - error - - message - - code - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Logout do usuário - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /auth/v1/logout: - post: - summary: Logout do usuário - deprecated: false - description: Encerrar sessão do usuário - tags: - - Authentication - - Authentication - parameters: [] - responses: - '204': - description: Logout realizado com sucesso - headers: {} - x-apidog-name: No Content - '401': - description: Token inválido - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - headers: {} - x-apidog-name: Unauthorized - security: - - bearer: [] - x-apidog-folder: Authentication - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940511-run -components: - schemas: - Error: - type: object - properties: - error: - type: string - message: - type: string - code: - type: string - x-apidog-orders: - - error - - message - - code - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Listar perfis de usuários - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /rest/v1/profiles: - get: - summary: Listar perfis de usuários - deprecated: false - description: '' - tags: - - Perfis - - Perfis - parameters: - - name: apikey - in: header - description: Chave da API Supabase - required: true - example: '' - schema: - type: string - responses: - '200': - description: Lista de perfis - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Profile' - headers: {} - x-apidog-name: OK - security: - - bearer: [] - x-apidog-folder: Perfis - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940522-run -components: - schemas: - Profile: - type: object - properties: - id: - type: string - format: uuid - full_name: - type: string - examples: - - Dr. João Silva - nullable: true - email: - type: string - format: email - nullable: true - phone: - type: string - examples: - - '+5511999999999' - nullable: true - avatar_url: - type: string - format: uri - nullable: true - disabled: - type: boolean - examples: - - false - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - x-apidog-orders: - - id - - full_name - - email - - phone - - avatar_url - - disabled - - created_at - - updated_at - x-apidog-ignore-properties: [] - nullable: true - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Atualizar perfil do usuário - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /rest/v1/profiles: - patch: - summary: Atualizar perfil do usuário - deprecated: false - description: '' - tags: - - Perfis - - Perfis - parameters: - - name: apikey - in: header - description: Chave da API Supabase - required: true - example: '' - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ProfileInput' - responses: - '200': - description: Perfil atualizado - content: - application/json: - schema: - $ref: '#/components/schemas/Profile' - headers: {} - x-apidog-name: OK - security: - - bearer: [] - x-apidog-folder: Perfis - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940523-run -components: - schemas: - ProfileInput: - type: object - properties: - full_name: - type: string - avatar_url: - type: string - phone: - type: string - x-apidog-orders: - - full_name - - avatar_url - - phone - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Profile: - type: object - properties: - id: - type: string - format: uuid - full_name: - type: string - examples: - - Dr. João Silva - nullable: true - email: - type: string - format: email - nullable: true - phone: - type: string - examples: - - '+5511999999999' - nullable: true - avatar_url: - type: string - format: uri - nullable: true - disabled: - type: boolean - examples: - - false - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - x-apidog-orders: - - id - - full_name - - email - - phone - - avatar_url - - disabled - - created_at - - updated_at - x-apidog-ignore-properties: [] - nullable: true - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Obter paciente por ID - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /rest/v1/patients/{id}: - get: - summary: Obter paciente por ID - deprecated: false - description: Retorna dados de um paciente específico - tags: - - Pacientes - - Pacientes - parameters: - - name: id - in: path - description: ID do paciente - required: true - example: '' - schema: - type: string - format: uuid - - name: apikey - in: header - description: Chave da API Supabase - required: true - example: '' - schema: - type: string - responses: - '200': - description: Dados do paciente - content: - application/json: - schema: - $ref: '#/components/schemas/Patient' - headers: {} - x-apidog-name: OK - '401': - description: Não autorizado - content: - application/json: - schema: &ref_0 - $ref: '#/components/schemas/Error' - headers: {} - x-apidog-name: Unauthorized - '404': - description: Paciente não encontrado - content: - application/json: - schema: *ref_0 - headers: {} - x-apidog-name: Not Found - security: - - bearer: [] - x-apidog-folder: Pacientes - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940515-run -components: - schemas: - Patient: - type: object - properties: - id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - full_name: - type: string - examples: - - Maria Santos Silva - cpf: - type: string - examples: - - '12345678901' - email: - type: string - format: email - examples: - - maria@email.com - phone_mobile: - type: string - examples: - - (11) 99999-9999 - birth_date: - type: string - format: date - examples: - - '1980-01-15' - social_name: - type: string - examples: - - Maria Santos - sex: - type: string - examples: - - F - blood_type: - type: string - examples: - - A+ - weight_kg: - type: number - examples: - - 65.5 - height_m: - type: number - examples: - - 1.65 - bmi: - type: number - examples: - - 24.1 - street: - type: string - examples: - - Rua das Flores, 123 - number: - type: string - examples: - - '123' - complement: - type: string - examples: - - Apt 45 - neighborhood: - type: string - examples: - - Centro - city: - type: string - examples: - - São Paulo - state: - type: string - examples: - - SP - cep: - type: string - examples: - - 01234-567 - created_at: - type: string - format: date-time - examples: - - '2024-01-15T10:30:00Z' - updated_at: - type: string - format: date-time - examples: - - '2024-01-15T10:30:00Z' - created_by: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - x-apidog-orders: - - id - - full_name - - cpf - - email - - phone_mobile - - birth_date - - social_name - - sex - - blood_type - - weight_kg - - height_m - - bmi - - street - - number - - complement - - neighborhood - - city - - state - - cep - - created_at - - updated_at - - created_by - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Error: - type: object - properties: - error: - type: string - message: - type: string - code: - type: string - x-apidog-orders: - - error - - message - - code - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Atualizar paciente - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /rest/v1/patients/{id}: - patch: - summary: Atualizar paciente - deprecated: false - description: Atualizar dados de um paciente existente - tags: - - Pacientes - - Pacientes - parameters: - - name: id - in: path - description: ID do paciente - required: true - example: '' - schema: - type: string - format: uuid - - name: apikey - in: header - description: Chave da API Supabase - required: true - example: '' - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/PatientInput' - responses: - '200': - description: Paciente atualizado com sucesso - content: - application/json: - schema: - $ref: '#/components/schemas/Patient' - headers: {} - x-apidog-name: OK - '401': - description: Não autorizado - content: - application/json: - schema: &ref_0 - $ref: '#/components/schemas/Error' - headers: {} - x-apidog-name: Unauthorized - '404': - description: Paciente não encontrado - content: - application/json: - schema: *ref_0 - headers: {} - x-apidog-name: Not Found - security: - - bearer: [] - x-apidog-folder: Pacientes - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940516-run -components: - schemas: - PatientInput: - type: object - required: - - full_name - - cpf - - email - - phone_mobile - properties: - full_name: - type: string - examples: - - Maria Santos Silva - cpf: - type: string - examples: - - '12345678901' - email: - type: string - format: email - examples: - - maria@email.com - phone_mobile: - type: string - examples: - - (11) 99999-9999 - birth_date: - type: string - format: date - examples: - - '1980-01-15' - social_name: - type: string - sex: - type: string - examples: - - F - blood_type: - type: string - weight_kg: - type: number - height_m: - type: number - street: - type: string - number: - type: string - complement: - type: string - neighborhood: - type: string - city: - type: string - state: - type: string - cep: - type: string - x-apidog-orders: - - full_name - - cpf - - email - - phone_mobile - - birth_date - - social_name - - sex - - blood_type - - weight_kg - - height_m - - street - - number - - complement - - neighborhood - - city - - state - - cep - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Patient: - type: object - properties: - id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - full_name: - type: string - examples: - - Maria Santos Silva - cpf: - type: string - examples: - - '12345678901' - email: - type: string - format: email - examples: - - maria@email.com - phone_mobile: - type: string - examples: - - (11) 99999-9999 - birth_date: - type: string - format: date - examples: - - '1980-01-15' - social_name: - type: string - examples: - - Maria Santos - sex: - type: string - examples: - - F - blood_type: - type: string - examples: - - A+ - weight_kg: - type: number - examples: - - 65.5 - height_m: - type: number - examples: - - 1.65 - bmi: - type: number - examples: - - 24.1 - street: - type: string - examples: - - Rua das Flores, 123 - number: - type: string - examples: - - '123' - complement: - type: string - examples: - - Apt 45 - neighborhood: - type: string - examples: - - Centro - city: - type: string - examples: - - São Paulo - state: - type: string - examples: - - SP - cep: - type: string - examples: - - 01234-567 - created_at: - type: string - format: date-time - examples: - - '2024-01-15T10:30:00Z' - updated_at: - type: string - format: date-time - examples: - - '2024-01-15T10:30:00Z' - created_by: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - x-apidog-orders: - - id - - full_name - - cpf - - email - - phone_mobile - - birth_date - - social_name - - sex - - blood_type - - weight_kg - - height_m - - bmi - - street - - number - - complement - - neighborhood - - city - - state - - cep - - created_at - - updated_at - - created_by - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Error: - type: object - properties: - error: - type: string - message: - type: string - code: - type: string - x-apidog-orders: - - error - - message - - code - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Deletar paciente - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /rest/v1/patients/{id}: - delete: - summary: Deletar paciente - deprecated: false - description: Remover um paciente do sistema (apenas admins/gestores) - tags: - - Pacientes - - Pacientes - parameters: - - name: id - in: path - description: ID do paciente - required: true - example: '' - schema: - type: string - format: uuid - - name: apikey - in: header - description: Chave da API Supabase - required: true - example: '' - schema: - type: string - responses: - '204': - description: Paciente deletado com sucesso - headers: {} - x-apidog-name: No Content - '401': - description: Não autorizado - content: - application/json: - schema: &ref_0 - $ref: '#/components/schemas/Error' - headers: {} - x-apidog-name: Unauthorized - '403': - description: Sem permissão - content: - application/json: - schema: *ref_0 - headers: {} - x-apidog-name: Forbidden - '404': - description: Paciente não encontrado - content: - application/json: - schema: *ref_0 - headers: {} - x-apidog-name: Not Found - security: - - bearer: [] - x-apidog-folder: Pacientes - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940517-run -components: - schemas: - Error: - type: object - properties: - error: - type: string - message: - type: string - code: - type: string - x-apidog-orders: - - error - - message - - code - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Criar novo paciente - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /rest/v1/patients: - post: - summary: Criar novo paciente - deprecated: false - description: Cadastrar um novo paciente no sistema - tags: - - Pacientes - - Pacientes - parameters: - - name: apikey - in: header - description: Chave da API Supabase - required: true - example: '{{API_KEY}}' - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/PatientInput' - example: - full_name: Maria Santos - cpf: '12345678901' - email: maria@email.com - phone_mobile: (11) 99999-9999 - birth_date: '1980-01-15' - responses: - '201': - description: Paciente criado com sucesso - content: - application/json: - schema: - $ref: '#/components/schemas/Patient' - headers: {} - x-apidog-name: Created - '400': - description: Dados inválidos - content: - application/json: - schema: &ref_0 - $ref: '#/components/schemas/Error' - headers: {} - x-apidog-name: Bad Request - '401': - description: Não autorizado - content: - application/json: - schema: *ref_0 - headers: {} - x-apidog-name: Unauthorized - security: - - bearer: [] - x-apidog-folder: Pacientes - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940514-run -components: - schemas: - PatientInput: - type: object - required: - - full_name - - cpf - - email - - phone_mobile - properties: - full_name: - type: string - examples: - - Maria Santos Silva - cpf: - type: string - examples: - - '12345678901' - email: - type: string - format: email - examples: - - maria@email.com - phone_mobile: - type: string - examples: - - (11) 99999-9999 - birth_date: - type: string - format: date - examples: - - '1980-01-15' - social_name: - type: string - sex: - type: string - examples: - - F - blood_type: - type: string - weight_kg: - type: number - height_m: - type: number - street: - type: string - number: - type: string - complement: - type: string - neighborhood: - type: string - city: - type: string - state: - type: string - cep: - type: string - x-apidog-orders: - - full_name - - cpf - - email - - phone_mobile - - birth_date - - social_name - - sex - - blood_type - - weight_kg - - height_m - - street - - number - - complement - - neighborhood - - city - - state - - cep - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Patient: - type: object - properties: - id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - full_name: - type: string - examples: - - Maria Santos Silva - cpf: - type: string - examples: - - '12345678901' - email: - type: string - format: email - examples: - - maria@email.com - phone_mobile: - type: string - examples: - - (11) 99999-9999 - birth_date: - type: string - format: date - examples: - - '1980-01-15' - social_name: - type: string - examples: - - Maria Santos - sex: - type: string - examples: - - F - blood_type: - type: string - examples: - - A+ - weight_kg: - type: number - examples: - - 65.5 - height_m: - type: number - examples: - - 1.65 - bmi: - type: number - examples: - - 24.1 - street: - type: string - examples: - - Rua das Flores, 123 - number: - type: string - examples: - - '123' - complement: - type: string - examples: - - Apt 45 - neighborhood: - type: string - examples: - - Centro - city: - type: string - examples: - - São Paulo - state: - type: string - examples: - - SP - cep: - type: string - examples: - - 01234-567 - created_at: - type: string - format: date-time - examples: - - '2024-01-15T10:30:00Z' - updated_at: - type: string - format: date-time - examples: - - '2024-01-15T10:30:00Z' - created_by: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - x-apidog-orders: - - id - - full_name - - cpf - - email - - phone_mobile - - birth_date - - social_name - - sex - - blood_type - - weight_kg - - height_m - - bmi - - street - - number - - complement - - neighborhood - - city - - state - - cep - - created_at - - updated_at - - created_by - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Error: - type: object - properties: - error: - type: string - message: - type: string - code: - type: string - x-apidog-orders: - - error - - message - - code - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` - -# Listar pacientes - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /rest/v1/patients: - get: - summary: Listar pacientes - deprecated: false - description: Retorna lista de pacientes com base nas permissões do usuário - tags: - - Pacientes - - Pacientes - parameters: - - name: apikey - in: header - description: '' - required: false - example: '{{apikey}}' - schema: - type: string - responses: - '200': - description: Lista de pacientes - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Patient' - headers: {} - x-apidog-name: OK - '401': - description: Não autorizado - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - headers: {} - x-apidog-name: Unauthorized - security: - - bearer: [] - x-apidog-folder: Pacientes - x-apidog-status: released - x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940513-run -components: - schemas: - Patient: - type: object - properties: - id: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - full_name: - type: string - examples: - - Maria Santos Silva - cpf: - type: string - examples: - - '12345678901' - email: - type: string - format: email - examples: - - maria@email.com - phone_mobile: - type: string - examples: - - (11) 99999-9999 - birth_date: - type: string - format: date - examples: - - '1980-01-15' - social_name: - type: string - examples: - - Maria Santos - sex: - type: string - examples: - - F - blood_type: - type: string - examples: - - A+ - weight_kg: - type: number - examples: - - 65.5 - height_m: - type: number - examples: - - 1.65 - bmi: - type: number - examples: - - 24.1 - street: - type: string - examples: - - Rua das Flores, 123 - number: - type: string - examples: - - '123' - complement: - type: string - examples: - - Apt 45 - neighborhood: - type: string - examples: - - Centro - city: - type: string - examples: - - São Paulo - state: - type: string - examples: - - SP - cep: - type: string - examples: - - 01234-567 - created_at: - type: string - format: date-time - examples: - - '2024-01-15T10:30:00Z' - updated_at: - type: string - format: date-time - examples: - - '2024-01-15T10:30:00Z' - created_by: - type: string - format: uuid - examples: - - 12345678-1234-1234-1234-123456789012 - x-apidog-orders: - - id - - full_name - - cpf - - email - - phone_mobile - - birth_date - - social_name - - sex - - blood_type - - weight_kg - - height_m - - bmi - - street - - number - - complement - - neighborhood - - city - - state - - cep - - created_at - - updated_at - - created_by - x-apidog-ignore-properties: [] - x-apidog-folder: '' - Error: - type: object - properties: - error: - type: string - message: - type: string - code: - type: string - x-apidog-orders: - - error - - message - - code - x-apidog-ignore-properties: [] - x-apidog-folder: '' - securitySchemes: - bearerAuth: - type: jwt - scheme: bearer - bearerFormat: JWT - description: Token JWT obtido no login - bearer: - type: http - scheme: bearer -servers: - - url: https://yuanqfswhberkoevtmfr.supabase.co - description: Prod Env - - url: '' - description: Cloud Mock -security: - - bearer: [] - -``` diff --git a/susconecta/app/(main-routes)/dashboard/page.tsx b/susconecta/app/(main-routes)/dashboard/page.tsx index ffd17fe..9d9c5c0 100644 --- a/susconecta/app/(main-routes)/dashboard/page.tsx +++ b/susconecta/app/(main-routes)/dashboard/page.tsx @@ -1,41 +1,403 @@ -export default function DashboardPage() { - return ( - <> -
-
-

Dashboard

-

- Bem-vindo ao painel de controle -

-
+'use client'; -
-
-

- Total de Pacientes -

-

1,234

-
-
-

- Consultas Hoje -

-

28

-
-
-

- Próximas Consultas -

-

45

-
-
-

- Receita Mensal -

-

R$ 45.230

+import { useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { + countTotalPatients, + countTotalDoctors, + countAppointmentsToday, + getUpcomingAppointments, + getAppointmentsByDateRange, + getNewUsersLastDays, + getPendingReports, + getDisabledUsers, + getDoctorsAvailabilityToday, + getPatientById, + getDoctorById, +} from '@/lib/api'; +import { Button } from '@/components/ui/button'; +import { Badge } from '@/components/ui/badge'; +import { Alert, AlertDescription } from '@/components/ui/alert'; +import { AlertCircle, Calendar, Users, Stethoscope, Clock, FileText, AlertTriangle, Plus, ArrowLeft } from 'lucide-react'; +import Link from 'next/link'; +import { PatientRegistrationForm } from '@/components/forms/patient-registration-form'; +import { DoctorRegistrationForm } from '@/components/forms/doctor-registration-form'; + +interface DashboardStats { + totalPatients: number; + totalDoctors: number; + appointmentsToday: number; +} + +interface UpcomingAppointment { + id: string; + scheduled_at: string; + status: string; + doctor_id: string; + patient_id: string; + doctor?: { full_name?: string }; + patient?: { full_name?: string }; +} + +export default function DashboardPage() { + const router = useRouter(); + const [stats, setStats] = useState({ + totalPatients: 0, + totalDoctors: 0, + appointmentsToday: 0, + }); + const [appointments, setAppointments] = useState([]); + const [appointmentData, setAppointmentData] = useState([]); + const [newUsers, setNewUsers] = useState([]); + const [pendingReports, setPendingReports] = useState([]); + const [disabledUsers, setDisabledUsers] = useState([]); + const [doctors, setDoctors] = useState>(new Map()); + const [patients, setPatients] = useState>(new Map()); + const [loading, setLoading] = useState(true); + + // Estados para os modais de formulário + const [showPatientForm, setShowPatientForm] = useState(false); + const [showDoctorForm, setShowDoctorForm] = useState(false); + const [editingPatientId, setEditingPatientId] = useState(null); + const [editingDoctorId, setEditingDoctorId] = useState(null); + + useEffect(() => { + loadDashboardData(); + }, []); + + const loadDashboardData = async () => { + try { + setLoading(true); + + // 1. Carrega stats + const [patientCount, doctorCount, todayCount] = await Promise.all([ + countTotalPatients(), + countTotalDoctors(), + countAppointmentsToday(), + ]); + + setStats({ + totalPatients: patientCount, + totalDoctors: doctorCount, + appointmentsToday: todayCount, + }); + + // 2. Carrega dados dos widgets em paralelo + const [upcomingAppts, appointmentDataRange, newUsersList, pendingReportsList, disabledUsersList] = await Promise.all([ + getUpcomingAppointments(5), + getAppointmentsByDateRange(7), + getNewUsersLastDays(7), + getPendingReports(5), + getDisabledUsers(5), + ]); + + setAppointments(upcomingAppts); + setAppointmentData(appointmentDataRange); + setNewUsers(newUsersList); + setPendingReports(pendingReportsList); + setDisabledUsers(disabledUsersList); + + // 3. Busca detalhes de pacientes e médicos para as próximas consultas + const doctorMap = new Map(); + const patientMap = new Map(); + + for (const appt of upcomingAppts) { + if (appt.doctor_id && !doctorMap.has(appt.doctor_id)) { + const doctor = await getDoctorById(appt.doctor_id); + if (doctor) doctorMap.set(appt.doctor_id, doctor); + } + if (appt.patient_id && !patientMap.has(appt.patient_id)) { + const patient = await getPatientById(appt.patient_id); + if (patient) patientMap.set(appt.patient_id, patient); + } + } + + setDoctors(doctorMap); + setPatients(patientMap); + } catch (err) { + console.error('[Dashboard] Erro ao carregar dados:', err); + } finally { + setLoading(false); + } + }; + + const handlePatientFormSaved = () => { + setShowPatientForm(false); + setEditingPatientId(null); + loadDashboardData(); + }; + + const handleDoctorFormSaved = () => { + setShowDoctorForm(false); + setEditingDoctorId(null); + loadDashboardData(); + }; + + const formatDate = (dateStr: string) => { + return new Date(dateStr).toLocaleDateString('pt-BR', { + day: '2-digit', + month: '2-digit', + hour: '2-digit', + minute: '2-digit', + }); + }; + + const getStatusBadge = (status: string) => { + const statusMap: Record = { + confirmed: { variant: 'default', label: 'Confirmado' }, + completed: { variant: 'secondary', label: 'Concluído' }, + cancelled: { variant: 'destructive', label: 'Cancelado' }, + requested: { variant: 'outline', label: 'Solicitado' }, + }; + const s = statusMap[status] || { variant: 'outline', label: status }; + return {s.label}; + }; + + if (loading) { + return ( +
+
+
+
+ {[1, 2, 3, 4].map(i => ( +
+ ))}
- + ); + } + + // Se está exibindo formulário de paciente + if (showPatientForm) { + return ( +
+
+ +

{editingPatientId ? "Editar paciente" : "Novo paciente"}

+
+ + { + setShowPatientForm(false); + setEditingPatientId(null); + }} + /> +
+ ); + } + + // Se está exibindo formulário de médico + if (showDoctorForm) { + return ( +
+
+ +

{editingDoctorId ? "Editar Médico" : "Novo Médico"}

+
+ + { + setShowDoctorForm(false); + setEditingDoctorId(null); + }} + /> +
+ ); + } + + return ( +
+ {/* Header */} +
+

Dashboard

+

Bem-vindo ao painel de controle

+
+ + {/* 1. CARDS RESUMO */} +
+
+
+
+

Total de Pacientes

+

{stats.totalPatients}

+
+ +
+
+ +
+
+
+

Total de Médicos

+

{stats.totalDoctors}

+
+ +
+
+ +
+
+
+

Consultas Hoje

+

{stats.appointmentsToday}

+
+ +
+
+ +
+
+
+

Relatórios Pendentes

+

{pendingReports.length}

+
+ +
+
+
+ + {/* 6. AÇÕES RÁPIDAS */} +
+

Ações Rápidas

+
+ + + + +
+
+ + {/* 2. PRÓXIMAS CONSULTAS */} +
+
+

Próximas Consultas (7 dias)

+ {appointments.length > 0 ? ( +
+ {appointments.map(appt => ( +
+
+

+ {patients.get(appt.patient_id)?.full_name || 'Paciente desconhecido'} +

+

+ Médico: {doctors.get(appt.doctor_id)?.full_name || 'Médico desconhecido'} +

+

{formatDate(appt.scheduled_at)}

+
+
+ {getStatusBadge(appt.status)} +
+
+ ))} +
+ ) : ( +

Nenhuma consulta agendada para os próximos 7 dias

+ )} +
+ + {/* 5. RELATÓRIOS PENDENTES */} +
+

+ + Relatórios Pendentes +

+ {pendingReports.length > 0 ? ( +
+ {pendingReports.map(report => ( +
+

{report.order_number}

+

{report.exam || 'Sem descrição'}

+
+ ))} + +
+ ) : ( +

Sem relatórios pendentes

+ )} +
+
+ + {/* 4. NOVOS USUÁRIOS */} +
+

Novos Usuários (últimos 7 dias)

+ {newUsers.length > 0 ? ( +
+ {newUsers.map(user => ( +
+

{user.full_name || 'Sem nome'}

+

{user.email}

+
+ ))} +
+ ) : ( +

Nenhum novo usuário nos últimos 7 dias

+ )} +
+ + {/* 8. ALERTAS */} + {disabledUsers.length > 0 && ( +
+

+ + Alertas - Usuários Desabilitados +

+
+ {disabledUsers.map(user => ( + + + + {user.full_name} ({user.email}) está desabilitado + + + ))} +
+
+ )} + + {/* 11. LINK PARA RELATÓRIOS */} +
+

Seção de Relatórios

+

+ Acesse a seção de relatórios médicos para gerenciar, visualizar e exportar documentos. +

+ +
+
); } + diff --git a/susconecta/lib/api.ts b/susconecta/lib/api.ts index 8860cb9..71758e6 100644 --- a/susconecta/lib/api.ts +++ b/susconecta/lib/api.ts @@ -2961,3 +2961,206 @@ export async function excluirPerfil(id: string | number): Promise { await parse(res); } +// ===== DASHBOARD WIDGETS ===== + +/** + * Busca contagem total de pacientes + */ +export async function countTotalPatients(): Promise { + try { + const url = `${REST}/patients?select=id&limit=1`; + const res = await fetch(url, { + headers: { + ...baseHeaders(), + 'Prefer': 'count=exact' + } + }); + const countHeader = res.headers.get('content-range'); + if (countHeader) { + const match = countHeader.match(/\/(\d+)$/); + return match ? parseInt(match[1]) : 0; + } + return 0; + } catch (err) { + console.error('[countTotalPatients] Erro:', err); + return 0; + } +} + +/** + * Busca contagem total de médicos + */ +export async function countTotalDoctors(): Promise { + try { + const url = `${REST}/doctors?select=id&limit=1`; + const res = await fetch(url, { + headers: { + ...baseHeaders(), + 'Prefer': 'count=exact' + } + }); + const countHeader = res.headers.get('content-range'); + if (countHeader) { + const match = countHeader.match(/\/(\d+)$/); + return match ? parseInt(match[1]) : 0; + } + return 0; + } catch (err) { + console.error('[countTotalDoctors] Erro:', err); + return 0; + } +} + +/** + * Busca contagem de agendamentos para hoje + */ +export async function countAppointmentsToday(): Promise { + try { + const today = new Date().toISOString().split('T')[0]; + const tomorrow = new Date(Date.now() + 86400000).toISOString().split('T')[0]; + + const url = `${REST}/appointments?scheduled_at=gte.${today}T00:00:00&scheduled_at=lt.${tomorrow}T00:00:00&select=id&limit=1`; + const res = await fetch(url, { + headers: { + ...baseHeaders(), + 'Prefer': 'count=exact' + } + }); + const countHeader = res.headers.get('content-range'); + if (countHeader) { + const match = countHeader.match(/\/(\d+)$/); + return match ? parseInt(match[1]) : 0; + } + return 0; + } catch (err) { + console.error('[countAppointmentsToday] Erro:', err); + return 0; + } +} + +/** + * Busca próximas consultas (próximos 7 dias) + */ +export async function getUpcomingAppointments(limit: number = 10): Promise { + try { + const today = new Date().toISOString(); + const nextWeek = new Date(Date.now() + 7 * 86400000).toISOString(); + + const url = `${REST}/appointments?scheduled_at=gte.${today}&scheduled_at=lt.${nextWeek}&order=scheduled_at.asc&limit=${limit}&select=id,scheduled_at,status,doctor_id,patient_id`; + const res = await fetch(url, { headers: baseHeaders() }); + return await parse(res); + } catch (err) { + console.error('[getUpcomingAppointments] Erro:', err); + return []; + } +} + +/** + * Busca agendamentos por data (para gráfico) + */ +export async function getAppointmentsByDateRange(days: number = 14): Promise { + try { + const startDate = new Date(); + startDate.setDate(startDate.getDate() - days); + const endDate = new Date().toISOString(); + + const url = `${REST}/appointments?scheduled_at=gte.${startDate.toISOString()}&scheduled_at=lt.${endDate}&select=scheduled_at,status&order=scheduled_at.asc`; + const res = await fetch(url, { headers: baseHeaders() }); + return await parse(res); + } catch (err) { + console.error('[getAppointmentsByDateRange] Erro:', err); + return []; + } +} + +/** + * Busca novos usuários (últimos 7 dias) + */ +export async function getNewUsersLastDays(days: number = 7): Promise { + try { + const startDate = new Date(); + startDate.setDate(startDate.getDate() - days); + + const url = `${REST}/profiles?created_at=gte.${startDate.toISOString()}&order=created_at.desc&limit=10&select=id,full_name,email`; + const res = await fetch(url, { headers: baseHeaders() }); + return await parse(res); + } catch (err) { + console.error('[getNewUsersLastDays] Erro:', err); + return []; + } +} + +/** + * Busca relatórios pendentes (draft) + */ +export async function getPendingReports(limit: number = 5): Promise { + try { + const url = `${REST}/reports?status=eq.draft&order=created_at.desc&limit=${limit}&select=id,order_number,patient_id,exam,requested_by,created_at`; + const res = await fetch(url, { headers: baseHeaders() }); + return await parse(res); + } catch (err) { + console.error('[getPendingReports] Erro:', err); + return []; + } +} + +/** + * Busca usuários desabilitados (alertas) + */ +export async function getDisabledUsers(limit: number = 5): Promise { + try { + const url = `${REST}/profiles?disabled=eq.true&order=updated_at.desc&limit=${limit}&select=id,full_name,email,disabled`; + const res = await fetch(url, { headers: baseHeaders() }); + return await parse(res); + } catch (err) { + console.error('[getDisabledUsers] Erro:', err); + return []; + } +} + +/** + * Busca disponibilidade de médicos (para hoje) + */ +export async function getDoctorsAvailabilityToday(): Promise { + try { + const today = new Date(); + const weekday = today.getDay(); + + const url = `${REST}/doctor_availability?weekday=eq.${weekday}&active=eq.true&select=id,doctor_id,start_time,end_time,slot_minutes,appointment_type`; + const res = await fetch(url, { headers: baseHeaders() }); + return await parse(res); + } catch (err) { + console.error('[getDoctorsAvailabilityToday] Erro:', err); + return []; + } +} + +/** + * Busca detalhes de paciente por ID + */ +export async function getPatientById(patientId: string): Promise { + try { + const url = `${REST}/patients?id=eq.${patientId}&select=*&limit=1`; + const res = await fetch(url, { headers: baseHeaders() }); + const arr = await parse(res); + return arr && arr.length > 0 ? arr[0] : null; + } catch (err) { + console.error('[getPatientById] Erro:', err); + return null; + } +} + +/** + * Busca detalhes de médico por ID + */ +export async function getDoctorById(doctorId: string): Promise { + try { + const url = `${REST}/doctors?id=eq.${doctorId}&select=*&limit=1`; + const res = await fetch(url, { headers: baseHeaders() }); + const arr = await parse(res); + return arr && arr.length > 0 ? arr[0] : null; + } catch (err) { + console.error('[getDoctorById] Erro:', err); + return null; + } +}