elevenlabs-webhook-nodejs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +27 -0
- package/.dockerignore +6 -0
- package/.env.example +43 -0
- package/BEFORE-PRODUCTION.md +32 -0
- package/Dockerfile +23 -0
- package/SYSTEM_OVERVIEW.md +942 -0
- package/SYSTEM_STATUS.md +332 -0
- package/backup_script/main.py +146 -0
- package/baileys/.dockerignore +7 -0
- package/baileys/Dockerfile +13 -0
- package/baileys/README.md +412 -0
- package/baileys/index.js +499 -0
- package/baileys/package-lock.json +2532 -0
- package/baileys/package.json +25 -0
- package/baileys/server.js +96 -0
- package/baileys/src/config.js +55 -0
- package/baileys/src/middleware/api-key.js +16 -0
- package/baileys/src/routes/accounts.js +51 -0
- package/baileys/src/routes/chats.js +103 -0
- package/baileys/src/routes/webhooks.js +34 -0
- package/baileys/src/services/account-store.js +259 -0
- package/baileys/src/services/webhook-dispatcher.js +161 -0
- package/baileys/src/services/worker-manager.js +597 -0
- package/baileys/src/utils/jid.js +79 -0
- package/baileys/src/utils/logger.js +16 -0
- package/baileys/src/utils/use-mongodb-auth-state.js +122 -0
- package/baileys/worker.js +721 -0
- package/dist/app.d.ts +1 -0
- package/dist/app.js +84 -0
- package/dist/app.js.map +1 -0
- package/dist/config/agentPrompts.json +19 -0
- package/dist/config/database.d.ts +1 -0
- package/dist/config/database.js +26 -0
- package/dist/config/database.js.map +1 -0
- package/dist/config/env.d.ts +41 -0
- package/dist/config/env.js +81 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.js +73 -0
- package/dist/config/index.js.map +1 -0
- package/dist/controllers/webhook.controller.d.ts +10 -0
- package/dist/controllers/webhook.controller.js +128 -0
- package/dist/controllers/webhook.controller.js.map +1 -0
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.js +13 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/hooks/webhookValidator.d.ts +2 -0
- package/dist/hooks/webhookValidator.js +47 -0
- package/dist/hooks/webhookValidator.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations/001_session-architecture.d.ts +3 -0
- package/dist/migrations/001_session-architecture.js +119 -0
- package/dist/migrations/001_session-architecture.js.map +1 -0
- package/dist/migrations/002_agent-ref.d.ts +3 -0
- package/dist/migrations/002_agent-ref.js +55 -0
- package/dist/migrations/002_agent-ref.js.map +1 -0
- package/dist/migrations/003_shift-schedule.d.ts +3 -0
- package/dist/migrations/003_shift-schedule.js +48 -0
- package/dist/migrations/003_shift-schedule.js.map +1 -0
- package/dist/migrations/004_invert-shift-to-clinic-hours.d.ts +3 -0
- package/dist/migrations/004_invert-shift-to-clinic-hours.js +27 -0
- package/dist/migrations/004_invert-shift-to-clinic-hours.js.map +1 -0
- package/dist/migrations/005_composite-baileys-chat-ids.d.ts +3 -0
- package/dist/migrations/005_composite-baileys-chat-ids.js +47 -0
- package/dist/migrations/005_composite-baileys-chat-ids.js.map +1 -0
- package/dist/migrations/migration.model.d.ts +18 -0
- package/dist/migrations/migration.model.js +45 -0
- package/dist/migrations/migration.model.js.map +1 -0
- package/dist/migrations/migration.routes.d.ts +2 -0
- package/dist/migrations/migration.routes.js +37 -0
- package/dist/migrations/migration.routes.js.map +1 -0
- package/dist/migrations/migration.runner.d.ts +19 -0
- package/dist/migrations/migration.runner.js +74 -0
- package/dist/migrations/migration.runner.js.map +1 -0
- package/dist/models/ConversationClaim.d.ts +13 -0
- package/dist/models/ConversationClaim.js +44 -0
- package/dist/models/ConversationClaim.js.map +1 -0
- package/dist/models/ConversationEvaluation.d.ts +23 -0
- package/dist/models/ConversationEvaluation.js +92 -0
- package/dist/models/ConversationEvaluation.js.map +1 -0
- package/dist/models/Summary.d.ts +37 -0
- package/dist/models/Summary.js +78 -0
- package/dist/models/Summary.js.map +1 -0
- package/dist/models/Transcription.d.ts +34 -0
- package/dist/models/Transcription.js +71 -0
- package/dist/models/Transcription.js.map +1 -0
- package/dist/models/WhatsAppRecipient.d.ts +23 -0
- package/dist/models/WhatsAppRecipient.js +53 -0
- package/dist/models/WhatsAppRecipient.js.map +1 -0
- package/dist/modules/admin/admin.routes.d.ts +2 -0
- package/dist/modules/admin/admin.routes.js +1966 -0
- package/dist/modules/admin/admin.routes.js.map +1 -0
- package/dist/modules/admin/elevenlabs-test-chat.routes.d.ts +2 -0
- package/dist/modules/admin/elevenlabs-test-chat.routes.js +158 -0
- package/dist/modules/admin/elevenlabs-test-chat.routes.js.map +1 -0
- package/dist/modules/admin/whatsapp-test-chat.routes.d.ts +2 -0
- package/dist/modules/admin/whatsapp-test-chat.routes.js +204 -0
- package/dist/modules/admin/whatsapp-test-chat.routes.js.map +1 -0
- package/dist/modules/agents/agent.model.d.ts +38 -0
- package/dist/modules/agents/agent.model.js +92 -0
- package/dist/modules/agents/agent.model.js.map +1 -0
- package/dist/modules/agents/agent.routes.d.ts +2 -0
- package/dist/modules/agents/agent.routes.js +61 -0
- package/dist/modules/agents/agent.routes.js.map +1 -0
- package/dist/modules/appointment-validation/appointment-validation.model.d.ts +76 -0
- package/dist/modules/appointment-validation/appointment-validation.model.js +118 -0
- package/dist/modules/appointment-validation/appointment-validation.model.js.map +1 -0
- package/dist/modules/appointment-validation/appointment-validation.routes.d.ts +2 -0
- package/dist/modules/appointment-validation/appointment-validation.routes.js +202 -0
- package/dist/modules/appointment-validation/appointment-validation.routes.js.map +1 -0
- package/dist/modules/appointment-validation/appointment-validation.service.d.ts +53 -0
- package/dist/modules/appointment-validation/appointment-validation.service.js +827 -0
- package/dist/modules/appointment-validation/appointment-validation.service.js.map +1 -0
- package/dist/modules/auth/auth.model.d.ts +17 -0
- package/dist/modules/auth/auth.model.js +64 -0
- package/dist/modules/auth/auth.model.js.map +1 -0
- package/dist/modules/auth/auth.routes.d.ts +2 -0
- package/dist/modules/auth/auth.routes.js +202 -0
- package/dist/modules/auth/auth.routes.js.map +1 -0
- package/dist/modules/auth/auth.service.d.ts +28 -0
- package/dist/modules/auth/auth.service.js +183 -0
- package/dist/modules/auth/auth.service.js.map +1 -0
- package/dist/modules/auth/refresh-token.model.d.ts +13 -0
- package/dist/modules/auth/refresh-token.model.js +52 -0
- package/dist/modules/auth/refresh-token.model.js.map +1 -0
- package/dist/modules/billing/billing-alert.model.d.ts +16 -0
- package/dist/modules/billing/billing-alert.model.js +47 -0
- package/dist/modules/billing/billing-alert.model.js.map +1 -0
- package/dist/modules/billing/billing-period-snapshot.model.d.ts +35 -0
- package/dist/modules/billing/billing-period-snapshot.model.js +68 -0
- package/dist/modules/billing/billing-period-snapshot.model.js.map +1 -0
- package/dist/modules/billing/billing.model.d.ts +18 -0
- package/dist/modules/billing/billing.model.js +62 -0
- package/dist/modules/billing/billing.model.js.map +1 -0
- package/dist/modules/billing/billing.routes.d.ts +2 -0
- package/dist/modules/billing/billing.routes.js +63 -0
- package/dist/modules/billing/billing.routes.js.map +1 -0
- package/dist/modules/billing/billing.service.d.ts +69 -0
- package/dist/modules/billing/billing.service.js +498 -0
- package/dist/modules/billing/billing.service.js.map +1 -0
- package/dist/modules/billing/payment.model.d.ts +24 -0
- package/dist/modules/billing/payment.model.js +57 -0
- package/dist/modules/billing/payment.model.js.map +1 -0
- package/dist/modules/calls/call.model.d.ts +41 -0
- package/dist/modules/calls/call.model.js +97 -0
- package/dist/modules/calls/call.model.js.map +1 -0
- package/dist/modules/calls/call.routes.d.ts +2 -0
- package/dist/modules/calls/call.routes.js +103 -0
- package/dist/modules/calls/call.routes.js.map +1 -0
- package/dist/modules/campaigns/campaign.model.d.ts +45 -0
- package/dist/modules/campaigns/campaign.model.js +98 -0
- package/dist/modules/campaigns/campaign.model.js.map +1 -0
- package/dist/modules/campaigns/campaign.routes.d.ts +2 -0
- package/dist/modules/campaigns/campaign.routes.js +323 -0
- package/dist/modules/campaigns/campaign.routes.js.map +1 -0
- package/dist/modules/campaigns/campaign.service.d.ts +11 -0
- package/dist/modules/campaigns/campaign.service.js +86 -0
- package/dist/modules/campaigns/campaign.service.js.map +1 -0
- package/dist/modules/google-calendar/google-calendar.routes.d.ts +2 -0
- package/dist/modules/google-calendar/google-calendar.routes.js +32 -0
- package/dist/modules/google-calendar/google-calendar.routes.js.map +1 -0
- package/dist/modules/inbound-call/inbound-call-config.model.d.ts +20 -0
- package/dist/modules/inbound-call/inbound-call-config.model.js +68 -0
- package/dist/modules/inbound-call/inbound-call-config.model.js.map +1 -0
- package/dist/modules/inbound-call/inbound-call.routes.d.ts +2 -0
- package/dist/modules/inbound-call/inbound-call.routes.js +243 -0
- package/dist/modules/inbound-call/inbound-call.routes.js.map +1 -0
- package/dist/modules/leads/lead.model.d.ts +24 -0
- package/dist/modules/leads/lead.model.js +54 -0
- package/dist/modules/leads/lead.model.js.map +1 -0
- package/dist/modules/leads/lead.routes.d.ts +2 -0
- package/dist/modules/leads/lead.routes.js +201 -0
- package/dist/modules/leads/lead.routes.js.map +1 -0
- package/dist/modules/plans/plan.model.d.ts +25 -0
- package/dist/modules/plans/plan.model.js +59 -0
- package/dist/modules/plans/plan.model.js.map +1 -0
- package/dist/modules/surveys/survey.model.d.ts +30 -0
- package/dist/modules/surveys/survey.model.js +75 -0
- package/dist/modules/surveys/survey.model.js.map +1 -0
- package/dist/modules/surveys/survey.routes.d.ts +2 -0
- package/dist/modules/surveys/survey.routes.js +153 -0
- package/dist/modules/surveys/survey.routes.js.map +1 -0
- package/dist/modules/tenants/tenant.model.d.ts +86 -0
- package/dist/modules/tenants/tenant.model.js +127 -0
- package/dist/modules/tenants/tenant.model.js.map +1 -0
- package/dist/modules/tenants/tenant.routes.d.ts +2 -0
- package/dist/modules/tenants/tenant.routes.js +65 -0
- package/dist/modules/tenants/tenant.routes.js.map +1 -0
- package/dist/modules/users/user.routes.d.ts +2 -0
- package/dist/modules/users/user.routes.js +106 -0
- package/dist/modules/users/user.routes.js.map +1 -0
- package/dist/modules/webhooks/elevenlabs-tool.routes.d.ts +20 -0
- package/dist/modules/webhooks/elevenlabs-tool.routes.js +85 -0
- package/dist/modules/webhooks/elevenlabs-tool.routes.js.map +1 -0
- package/dist/modules/webhooks/elevenlabs-tool.service.d.ts +11 -0
- package/dist/modules/webhooks/elevenlabs-tool.service.js +360 -0
- package/dist/modules/webhooks/elevenlabs-tool.service.js.map +1 -0
- package/dist/modules/webhooks/elevenlabs.routes.d.ts +2 -0
- package/dist/modules/webhooks/elevenlabs.routes.js +34 -0
- package/dist/modules/webhooks/elevenlabs.routes.js.map +1 -0
- package/dist/modules/webhooks/elevenlabs.service.d.ts +6 -0
- package/dist/modules/webhooks/elevenlabs.service.js +512 -0
- package/dist/modules/webhooks/elevenlabs.service.js.map +1 -0
- package/dist/modules/webhooks/unipile.routes.d.ts +2 -0
- package/dist/modules/webhooks/unipile.routes.js +780 -0
- package/dist/modules/webhooks/unipile.routes.js.map +1 -0
- package/dist/modules/whatsapp/appointment.model.d.ts +27 -0
- package/dist/modules/whatsapp/appointment.model.js +58 -0
- package/dist/modules/whatsapp/appointment.model.js.map +1 -0
- package/dist/modules/whatsapp/operator-request.model.d.ts +29 -0
- package/dist/modules/whatsapp/operator-request.model.js +65 -0
- package/dist/modules/whatsapp/operator-request.model.js.map +1 -0
- package/dist/modules/whatsapp/stt-usage.model.d.ts +16 -0
- package/dist/modules/whatsapp/stt-usage.model.js +53 -0
- package/dist/modules/whatsapp/stt-usage.model.js.map +1 -0
- package/dist/modules/whatsapp/whatsapp-chat.model.d.ts +23 -0
- package/dist/modules/whatsapp/whatsapp-chat.model.js +55 -0
- package/dist/modules/whatsapp/whatsapp-chat.model.js.map +1 -0
- package/dist/modules/whatsapp/whatsapp-contact-profile.model.d.ts +23 -0
- package/dist/modules/whatsapp/whatsapp-contact-profile.model.js +54 -0
- package/dist/modules/whatsapp/whatsapp-contact-profile.model.js.map +1 -0
- package/dist/modules/whatsapp/whatsapp-message.model.d.ts +30 -0
- package/dist/modules/whatsapp/whatsapp-message.model.js +52 -0
- package/dist/modules/whatsapp/whatsapp-message.model.js.map +1 -0
- package/dist/modules/whatsapp/whatsapp-session.model.d.ts +33 -0
- package/dist/modules/whatsapp/whatsapp-session.model.js +65 -0
- package/dist/modules/whatsapp/whatsapp-session.model.js.map +1 -0
- package/dist/modules/whatsapp/whatsapp.routes.d.ts +2 -0
- package/dist/modules/whatsapp/whatsapp.routes.js +1237 -0
- package/dist/modules/whatsapp/whatsapp.routes.js.map +1 -0
- package/dist/plugins/cors.d.ts +3 -0
- package/dist/plugins/cors.js +11 -0
- package/dist/plugins/cors.js.map +1 -0
- package/dist/plugins/jwt.d.ts +3 -0
- package/dist/plugins/jwt.js +22 -0
- package/dist/plugins/jwt.js.map +1 -0
- package/dist/plugins/rawBody.d.ts +3 -0
- package/dist/plugins/rawBody.js +16 -0
- package/dist/plugins/rawBody.js.map +1 -0
- package/dist/plugins/rbac.d.ts +5 -0
- package/dist/plugins/rbac.js +29 -0
- package/dist/plugins/rbac.js.map +1 -0
- package/dist/routes/admin.routes.d.ts +2 -0
- package/dist/routes/admin.routes.js +169 -0
- package/dist/routes/admin.routes.js.map +1 -0
- package/dist/routes/health.routes.d.ts +2 -0
- package/dist/routes/health.routes.js +16 -0
- package/dist/routes/health.routes.js.map +1 -0
- package/dist/routes/webhook.routes.d.ts +2 -0
- package/dist/routes/webhook.routes.js +17 -0
- package/dist/routes/webhook.routes.js.map +1 -0
- package/dist/services/ai/base.ai.d.ts +19 -0
- package/dist/services/ai/base.ai.js +120 -0
- package/dist/services/ai/base.ai.js.map +1 -0
- package/dist/services/ai/gemini.service.d.ts +11 -0
- package/dist/services/ai/gemini.service.js +43 -0
- package/dist/services/ai/gemini.service.js.map +1 -0
- package/dist/services/ai/index.d.ts +2 -0
- package/dist/services/ai/index.js +26 -0
- package/dist/services/ai/index.js.map +1 -0
- package/dist/services/ai/openai.service.d.ts +11 -0
- package/dist/services/ai/openai.service.js +50 -0
- package/dist/services/ai/openai.service.js.map +1 -0
- package/dist/services/elevenlabs.service.d.ts +52 -0
- package/dist/services/elevenlabs.service.js +447 -0
- package/dist/services/elevenlabs.service.js.map +1 -0
- package/dist/services/google-calendar.service.d.ts +60 -0
- package/dist/services/google-calendar.service.js +494 -0
- package/dist/services/google-calendar.service.js.map +1 -0
- package/dist/services/inbound-call-schedule.service.d.ts +11 -0
- package/dist/services/inbound-call-schedule.service.js +162 -0
- package/dist/services/inbound-call-schedule.service.js.map +1 -0
- package/dist/services/netgsm.service.d.ts +41 -0
- package/dist/services/netgsm.service.js +89 -0
- package/dist/services/netgsm.service.js.map +1 -0
- package/dist/services/unipile.service.d.ts +41 -0
- package/dist/services/unipile.service.js +149 -0
- package/dist/services/unipile.service.js.map +1 -0
- package/dist/services/whatsapp-agent.service.d.ts +139 -0
- package/dist/services/whatsapp-agent.service.js +2055 -0
- package/dist/services/whatsapp-agent.service.js.map +1 -0
- package/dist/services/whatsapp.service.d.ts +26 -0
- package/dist/services/whatsapp.service.js +206 -0
- package/dist/services/whatsapp.service.js.map +1 -0
- package/dist/templates/index.d.ts +39 -0
- package/dist/templates/index.js +35 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/receptionist.d.ts +2 -0
- package/dist/templates/receptionist.js +39 -0
- package/dist/templates/receptionist.js.map +1 -0
- package/dist/templates/survey.d.ts +2 -0
- package/dist/templates/survey.js +41 -0
- package/dist/templates/survey.js.map +1 -0
- package/dist/types/index.d.ts +173 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.js +105 -0
- package/dist/utils/logger.js.map +1 -0
- package/docker-compose.nestjs.yml +89 -0
- package/docker-compose.yml +78 -0
- package/docs/AI_AGENT_ENHANCEMENT_PLAN.md +164 -0
- package/docs/API.md +1193 -0
- package/docs/API_ENDPOINTS.md +344 -0
- package/docs/ARCHITECTURE.md +305 -0
- package/docs/AUTH_API.md +252 -0
- package/docs/BILLING_SMS_ALERTS.md +94 -0
- package/docs/CHAT_ASSIGNMENT_SYSTEM.md +118 -0
- package/docs/CLIENT_TOOLS_AND_FEATURES.md +337 -0
- package/docs/ELEVENLABS_WEBHOOK_TOOLS.md +644 -0
- package/docs/FRONTEND_CHECKLIST.md +227 -0
- package/docs/IMPLEMENTATION_STATUS.md +470 -0
- package/docs/MIGRATION_GUIDE.md +96 -0
- package/docs/MISSINGS_REPORT.md +507 -0
- package/docs/NESTJS_MIGRATION_REFERENCE.md +5136 -0
- package/docs/PROJECT_DESCRIPTION.md +1038 -0
- package/docs/SCALING.md +148 -0
- package/docs/SESSION_SUMMARY_2026_03_17.md +135 -0
- package/docs/WHATSAPP_AGENT.md +1086 -0
- package/docs/architecture/00-SYSTEM-OVERVIEW.md +318 -0
- package/docs/architecture/01-DATABASE-SCHEMA.md +2564 -0
- package/docs/architecture/02-AUTHENTICATION.md +1040 -0
- package/docs/architecture/03-MULTI-CLINIC.md +742 -0
- package/docs/architecture/04-WHATSAPP-AGENT.md +608 -0
- package/docs/architecture/05-OPERATOR-WORKFLOW.md +444 -0
- package/docs/architecture/06-BAILEYS-MICROSERVICE.md +616 -0
- package/docs/architecture/07-APPOINTMENTS.md +849 -0
- package/docs/architecture/08-VOICE-CALLS.md +470 -0
- package/docs/architecture/09-OUTBOUND-CAMPAIGNS.md +542 -0
- package/docs/architecture/10-CLIENT-TOOLS.md +665 -0
- package/docs/architecture/11-BILLING.md +458 -0
- package/docs/architecture/12-SECURITY.md +216 -0
- package/docs/architecture/13-LOGGING-AUDIT.md +549 -0
- package/docs/architecture/14-META-BUSINESS-API.md +454 -0
- package/docs/architecture/15-AI-MODULE.md +479 -0
- package/docs/architecture/16-BACKGROUND-JOBS.md +469 -0
- package/docs/architecture/17-REALTIME-LIVECHAT.md +447 -0
- package/docs/architecture/18-FILE-STORAGE.md +410 -0
- package/docs/architecture/19-PATIENTS.md +1034 -0
- package/docs/architecture/20-TREATMENTS-AND-PLANS.md +774 -0
- package/docs/architecture/21-BEFORE-AFTER-PHOTOS.md +519 -0
- package/docs/database.md +456 -0
- package/docs/ornek-randevu-onay.csv +3 -0
- package/ecosystem.config.js +16 -0
- package/elevenlabs-convai-api-reference.md +1171 -0
- package/frontend/.dockerignore +2 -0
- package/frontend/Dockerfile +24 -0
- package/frontend/README.md +75 -0
- package/frontend/components.json +25 -0
- package/frontend/eslint.config.js +23 -0
- package/frontend/index.html +13 -0
- package/frontend/nginx.conf +37 -0
- package/frontend/package-lock.json +8709 -0
- package/frontend/package.json +71 -0
- package/frontend/public/favicon.svg +1 -0
- package/frontend/public/icons.svg +24 -0
- package/frontend/src/App.tsx +125 -0
- package/frontend/src/components/error-boundary.tsx +50 -0
- package/frontend/src/components/shared/activity-timeline.tsx +66 -0
- package/frontend/src/components/shared/appointment-calendar.css +80 -0
- package/frontend/src/components/shared/appointment-calendar.tsx +245 -0
- package/frontend/src/components/shared/chat-bubble.tsx +72 -0
- package/frontend/src/components/shared/combobox.tsx +119 -0
- package/frontend/src/components/shared/confirm-dialog.tsx +57 -0
- package/frontend/src/components/shared/data-table-pagination.tsx +97 -0
- package/frontend/src/components/shared/data-table-toolbar.tsx +39 -0
- package/frontend/src/components/shared/empty-state.tsx +27 -0
- package/frontend/src/components/shared/file-upload.tsx +140 -0
- package/frontend/src/components/shared/index.ts +20 -0
- package/frontend/src/components/shared/language-switcher.tsx +29 -0
- package/frontend/src/components/shared/notification-dropdown.tsx +115 -0
- package/frontend/src/components/shared/page-header.tsx +23 -0
- package/frontend/src/components/shared/stat-card.tsx +37 -0
- package/frontend/src/components/shared/status-badge.tsx +70 -0
- package/frontend/src/components/shared/status-dot.tsx +43 -0
- package/frontend/src/components/ui/alert-dialog.tsx +187 -0
- package/frontend/src/components/ui/alert.tsx +76 -0
- package/frontend/src/components/ui/avatar.tsx +109 -0
- package/frontend/src/components/ui/badge.tsx +52 -0
- package/frontend/src/components/ui/breadcrumb.tsx +125 -0
- package/frontend/src/components/ui/button.tsx +60 -0
- package/frontend/src/components/ui/calendar.tsx +219 -0
- package/frontend/src/components/ui/card.tsx +103 -0
- package/frontend/src/components/ui/chart.tsx +371 -0
- package/frontend/src/components/ui/checkbox.tsx +29 -0
- package/frontend/src/components/ui/collapsible.tsx +19 -0
- package/frontend/src/components/ui/command.tsx +194 -0
- package/frontend/src/components/ui/dialog.tsx +158 -0
- package/frontend/src/components/ui/dropdown-menu.tsx +268 -0
- package/frontend/src/components/ui/input-group.tsx +156 -0
- package/frontend/src/components/ui/input.tsx +20 -0
- package/frontend/src/components/ui/label.tsx +20 -0
- package/frontend/src/components/ui/pagination.tsx +130 -0
- package/frontend/src/components/ui/popover.tsx +90 -0
- package/frontend/src/components/ui/progress.tsx +83 -0
- package/frontend/src/components/ui/radio-group.tsx +36 -0
- package/frontend/src/components/ui/scroll-area.tsx +54 -0
- package/frontend/src/components/ui/select.tsx +199 -0
- package/frontend/src/components/ui/separator.tsx +23 -0
- package/frontend/src/components/ui/sheet.tsx +138 -0
- package/frontend/src/components/ui/sidebar.tsx +723 -0
- package/frontend/src/components/ui/skeleton.tsx +13 -0
- package/frontend/src/components/ui/sonner.tsx +47 -0
- package/frontend/src/components/ui/switch.tsx +30 -0
- package/frontend/src/components/ui/table.tsx +114 -0
- package/frontend/src/components/ui/tabs.tsx +82 -0
- package/frontend/src/components/ui/textarea.tsx +18 -0
- package/frontend/src/components/ui/toggle-group.tsx +89 -0
- package/frontend/src/components/ui/toggle.tsx +43 -0
- package/frontend/src/components/ui/tooltip.tsx +64 -0
- package/frontend/src/hooks/use-mobile.ts +19 -0
- package/frontend/src/i18n/index.ts +20 -0
- package/frontend/src/i18n/locales/en.json +786 -0
- package/frontend/src/i18n/locales/tr.json +786 -0
- package/frontend/src/index.css +134 -0
- package/frontend/src/layouts/admin-layout.tsx +111 -0
- package/frontend/src/layouts/app-header.tsx +130 -0
- package/frontend/src/layouts/app-layout.tsx +19 -0
- package/frontend/src/layouts/app-sidebar.tsx +212 -0
- package/frontend/src/layouts/auth-guard.tsx +31 -0
- package/frontend/src/layouts/mobile-sidebar.tsx +120 -0
- package/frontend/src/lib/api.ts +68 -0
- package/frontend/src/lib/hooks/use-appointments.ts +224 -0
- package/frontend/src/lib/hooks/use-availability-blocks.ts +83 -0
- package/frontend/src/lib/hooks/use-chats.ts +236 -0
- package/frontend/src/lib/hooks/use-clinic-detail.ts +171 -0
- package/frontend/src/lib/hooks/use-clinics.ts +37 -0
- package/frontend/src/lib/hooks/use-doctor-calendar.ts +80 -0
- package/frontend/src/lib/hooks/use-examinations.ts +89 -0
- package/frontend/src/lib/hooks/use-medical-history.ts +52 -0
- package/frontend/src/lib/hooks/use-patients.ts +296 -0
- package/frontend/src/lib/hooks/use-photo-sets.ts +118 -0
- package/frontend/src/lib/hooks/use-treatment-plans.ts +152 -0
- package/frontend/src/lib/hooks/use-treatments.ts +125 -0
- package/frontend/src/lib/hooks/use-users.ts +172 -0
- package/frontend/src/lib/utils.ts +6 -0
- package/frontend/src/main.tsx +17 -0
- package/frontend/src/pages/admin/agents/detail.tsx +774 -0
- package/frontend/src/pages/admin/agents/import.tsx +280 -0
- package/frontend/src/pages/admin/agents/index.tsx +245 -0
- package/frontend/src/pages/admin/ai-playground.tsx +543 -0
- package/frontend/src/pages/appointments/create-appointment-dialog.tsx +390 -0
- package/frontend/src/pages/appointments/index.tsx +860 -0
- package/frontend/src/pages/audit/index.tsx +24 -0
- package/frontend/src/pages/auth/login.tsx +194 -0
- package/frontend/src/pages/billing/index.tsx +24 -0
- package/frontend/src/pages/calendar/index.tsx +704 -0
- package/frontend/src/pages/calendar-connections/index.tsx +295 -0
- package/frontend/src/pages/calls/index.tsx +24 -0
- package/frontend/src/pages/campaigns/index.tsx +24 -0
- package/frontend/src/pages/chats/index.tsx +981 -0
- package/frontend/src/pages/clinics/index.tsx +224 -0
- package/frontend/src/pages/clinics/settings.tsx +412 -0
- package/frontend/src/pages/components-showcase.tsx +773 -0
- package/frontend/src/pages/connections/index.tsx +328 -0
- package/frontend/src/pages/dashboard.tsx +50 -0
- package/frontend/src/pages/leads/index.tsx +24 -0
- package/frontend/src/pages/my-schedule/index.tsx +496 -0
- package/frontend/src/pages/patients/create-patient-dialog.tsx +358 -0
- package/frontend/src/pages/patients/detail.tsx +1195 -0
- package/frontend/src/pages/patients/edit-patient-dialog.tsx +387 -0
- package/frontend/src/pages/patients/examinations-tab.tsx +460 -0
- package/frontend/src/pages/patients/index.tsx +381 -0
- package/frontend/src/pages/patients/medical-history-dialog.tsx +207 -0
- package/frontend/src/pages/patients/photo-sets-tab.tsx +616 -0
- package/frontend/src/pages/patients/timeline-tab.tsx +164 -0
- package/frontend/src/pages/patients/treatment-plans-tab.tsx +598 -0
- package/frontend/src/pages/phone-numbers/detail.tsx +427 -0
- package/frontend/src/pages/phone-numbers/index.tsx +455 -0
- package/frontend/src/pages/platform/index.tsx +454 -0
- package/frontend/src/pages/settings/index.tsx +126 -0
- package/frontend/src/pages/treatments/index.tsx +487 -0
- package/frontend/src/pages/users/doctor-profile.tsx +672 -0
- package/frontend/src/pages/users/edit.tsx +329 -0
- package/frontend/src/pages/users/index.tsx +407 -0
- package/frontend/src/pages/validation/index.tsx +24 -0
- package/frontend/src/stores/auth.store.ts +108 -0
- package/frontend/src/stores/ui.store.ts +41 -0
- package/frontend/tsconfig.app.json +32 -0
- package/frontend/tsconfig.json +13 -0
- package/frontend/tsconfig.node.json +26 -0
- package/frontend/vite.config.ts +29 -0
- package/nestjs/.dockerignore +5 -0
- package/nestjs/.env.docker +64 -0
- package/nestjs/.prettierrc +4 -0
- package/nestjs/Dockerfile +36 -0
- package/nestjs/README.md +98 -0
- package/nestjs/eslint.config.mjs +35 -0
- package/nestjs/nest-cli.json +8 -0
- package/nestjs/package-lock.json +13390 -0
- package/nestjs/package.json +114 -0
- package/nestjs/prisma/migrations/20260409161536_add_message_metadata_fields/migration.sql +1746 -0
- package/nestjs/prisma/migrations/20260410140436_add_agent_ai_fields/migration.sql +36 -0
- package/nestjs/prisma/migrations/20260410175519_add_agent_clinic_assignments/migration.sql +21 -0
- package/nestjs/prisma/migrations/20260412094344_make_agent_tenant_optional/migration.sql +2 -0
- package/nestjs/prisma/migrations/20260412110008_add_admin_chat_sessions/migration.sql +47 -0
- package/nestjs/prisma/migrations/migration_lock.toml +3 -0
- package/nestjs/prisma/schema.prisma +1843 -0
- package/nestjs/prisma/seed.ts +375 -0
- package/nestjs/prisma.config.ts +14 -0
- package/nestjs/src/admin/admin.controller.ts +27 -0
- package/nestjs/src/admin/admin.module.ts +16 -0
- package/nestjs/src/admin/admin.service.ts +91 -0
- package/nestjs/src/admin/ai-chat-session.service.ts +454 -0
- package/nestjs/src/admin/ai-test.controller.ts +191 -0
- package/nestjs/src/admin/superadmin.controller.ts +106 -0
- package/nestjs/src/agents/agents.controller.ts +262 -0
- package/nestjs/src/agents/agents.module.ts +13 -0
- package/nestjs/src/agents/agents.service.ts +733 -0
- package/nestjs/src/agents/dto/create-agent.dto.ts +99 -0
- package/nestjs/src/agents/dto/index.ts +2 -0
- package/nestjs/src/agents/dto/update-agent.dto.ts +148 -0
- package/nestjs/src/app.module.ts +115 -0
- package/nestjs/src/appointment-validation/appointment-validation.controller.ts +194 -0
- package/nestjs/src/appointment-validation/appointment-validation.module.ts +16 -0
- package/nestjs/src/appointment-validation/appointment-validation.service.ts +450 -0
- package/nestjs/src/appointment-validation/dto/create-batch.dto.ts +105 -0
- package/nestjs/src/appointment-validation/dto/index.ts +1 -0
- package/nestjs/src/appointment-validation/processors/validation-dispatch.processor.ts +26 -0
- package/nestjs/src/appointment-validation/processors/validation-sync.processor.ts +23 -0
- package/nestjs/src/appointments/appointments.controller.ts +268 -0
- package/nestjs/src/appointments/appointments.module.ts +13 -0
- package/nestjs/src/appointments/appointments.service.ts +773 -0
- package/nestjs/src/appointments/dto/create-appointment.dto.ts +72 -0
- package/nestjs/src/appointments/dto/index.ts +4 -0
- package/nestjs/src/appointments/dto/query-appointments.dto.ts +60 -0
- package/nestjs/src/appointments/dto/update-appointment.dto.ts +43 -0
- package/nestjs/src/appointments/dto/update-status.dto.ts +18 -0
- package/nestjs/src/appointments/processors/reminder.processor.ts +243 -0
- package/nestjs/src/audit/audit.controller.ts +84 -0
- package/nestjs/src/audit/audit.decorator.ts +20 -0
- package/nestjs/src/audit/audit.interceptor.ts +67 -0
- package/nestjs/src/audit/audit.interfaces.ts +15 -0
- package/nestjs/src/audit/audit.module.ts +12 -0
- package/nestjs/src/audit/audit.service.ts +177 -0
- package/nestjs/src/auth/auth.controller.ts +116 -0
- package/nestjs/src/auth/auth.module.ts +25 -0
- package/nestjs/src/auth/auth.service.ts +612 -0
- package/nestjs/src/auth/dto/change-password.dto.ts +13 -0
- package/nestjs/src/auth/dto/forgot-password.dto.ts +8 -0
- package/nestjs/src/auth/dto/index.ts +6 -0
- package/nestjs/src/auth/dto/login.dto.ts +13 -0
- package/nestjs/src/auth/dto/refresh.dto.ts +8 -0
- package/nestjs/src/auth/dto/register.dto.ts +28 -0
- package/nestjs/src/auth/dto/reset-password.dto.ts +13 -0
- package/nestjs/src/auth/permissions.config.ts +85 -0
- package/nestjs/src/availability-blocks/availability-blocks.controller.ts +83 -0
- package/nestjs/src/availability-blocks/availability-blocks.module.ts +10 -0
- package/nestjs/src/availability-blocks/availability-blocks.service.ts +202 -0
- package/nestjs/src/billing/billing.controller.ts +104 -0
- package/nestjs/src/billing/billing.module.ts +12 -0
- package/nestjs/src/billing/billing.service.ts +398 -0
- package/nestjs/src/billing/dto/index.ts +2 -0
- package/nestjs/src/billing/dto/query-billing.dto.ts +29 -0
- package/nestjs/src/billing/dto/record-payment.dto.ts +60 -0
- package/nestjs/src/billing/processors/alerts.processor.ts +216 -0
- package/nestjs/src/billing/processors/snapshot.processor.ts +181 -0
- package/nestjs/src/calls/calls.controller.ts +92 -0
- package/nestjs/src/calls/calls.module.ts +10 -0
- package/nestjs/src/calls/calls.service.ts +359 -0
- package/nestjs/src/calls/dto/index.ts +1 -0
- package/nestjs/src/calls/dto/query-calls.dto.ts +46 -0
- package/nestjs/src/clinics/clinics.controller.ts +226 -0
- package/nestjs/src/clinics/clinics.module.ts +11 -0
- package/nestjs/src/clinics/clinics.service.ts +203 -0
- package/nestjs/src/clinics/dto/create-clinic.dto.ts +40 -0
- package/nestjs/src/clinics/dto/create-meta-connection.dto.ts +44 -0
- package/nestjs/src/clinics/dto/index.ts +4 -0
- package/nestjs/src/clinics/dto/update-clinic.dto.ts +133 -0
- package/nestjs/src/clinics/dto/update-meta-connection.dto.ts +22 -0
- package/nestjs/src/clinics/meta-connections.service.ts +210 -0
- package/nestjs/src/common/decorators/accessible-clinics.decorator.ts +9 -0
- package/nestjs/src/common/decorators/current-user.decorator.ts +10 -0
- package/nestjs/src/common/decorators/features.decorator.ts +7 -0
- package/nestjs/src/common/decorators/index.ts +4 -0
- package/nestjs/src/common/decorators/permissions.decorator.ts +13 -0
- package/nestjs/src/common/gateways/events.gateway.ts +157 -0
- package/nestjs/src/common/guards/clinic-access.guard.ts +40 -0
- package/nestjs/src/common/guards/features.guard.ts +38 -0
- package/nestjs/src/common/guards/index.ts +5 -0
- package/nestjs/src/common/guards/jwt-auth.guard.ts +54 -0
- package/nestjs/src/common/guards/permissions.guard.ts +50 -0
- package/nestjs/src/common/guards/superadmin.guard.ts +35 -0
- package/nestjs/src/common/interceptors/request-context.interceptor.ts +32 -0
- package/nestjs/src/common/interceptors/superadmin-tenant.interceptor.ts +42 -0
- package/nestjs/src/common/interfaces/jwt-payload.interface.ts +11 -0
- package/nestjs/src/config/config.module.ts +13 -0
- package/nestjs/src/database/database.module.ts +9 -0
- package/nestjs/src/database/prisma.service.ts +20 -0
- package/nestjs/src/database/tenant-context.ts +27 -0
- package/nestjs/src/google-calendar/google-calendar.controller.ts +259 -0
- package/nestjs/src/google-calendar/google-calendar.module.ts +10 -0
- package/nestjs/src/google-calendar/google-calendar.service.ts +811 -0
- package/nestjs/src/integrations/ai/ai.interface.ts +74 -0
- package/nestjs/src/integrations/ai/ai.module.ts +11 -0
- package/nestjs/src/integrations/ai/ai.service.ts +148 -0
- package/nestjs/src/integrations/ai/providers/anthropic.provider.ts +146 -0
- package/nestjs/src/integrations/ai/providers/openai.provider.ts +158 -0
- package/nestjs/src/integrations/elevenlabs/elevenlabs.module.ts +8 -0
- package/nestjs/src/integrations/elevenlabs/elevenlabs.service.ts +226 -0
- package/nestjs/src/integrations/encryption/encryption.module.ts +9 -0
- package/nestjs/src/integrations/encryption/encryption.service.ts +31 -0
- package/nestjs/src/integrations/image/image.module.ts +9 -0
- package/nestjs/src/integrations/image/image.service.ts +61 -0
- package/nestjs/src/integrations/meta-business/meta-business.module.ts +10 -0
- package/nestjs/src/integrations/meta-business/meta-instagram.service.ts +94 -0
- package/nestjs/src/integrations/meta-business/meta-webhook.service.ts +52 -0
- package/nestjs/src/integrations/meta-business/meta-whatsapp.service.ts +254 -0
- package/nestjs/src/integrations/minio/minio.module.ts +9 -0
- package/nestjs/src/integrations/minio/minio.service.ts +88 -0
- package/nestjs/src/integrations/netgsm/netgsm.module.ts +8 -0
- package/nestjs/src/integrations/netgsm/netgsm.service.ts +17 -0
- package/nestjs/src/integrations/tektippay/tektippay.module.ts +8 -0
- package/nestjs/src/integrations/tektippay/tektippay.service.ts +23 -0
- package/nestjs/src/leads/dto/index.ts +2 -0
- package/nestjs/src/leads/dto/query-leads.dto.ts +50 -0
- package/nestjs/src/leads/dto/update-lead.dto.ts +26 -0
- package/nestjs/src/leads/leads.controller.ts +184 -0
- package/nestjs/src/leads/leads.module.ts +10 -0
- package/nestjs/src/leads/leads.service.ts +375 -0
- package/nestjs/src/logging/logging.controller.ts +82 -0
- package/nestjs/src/logging/logging.module.ts +11 -0
- package/nestjs/src/logging/logging.service.ts +180 -0
- package/nestjs/src/main.ts +86 -0
- package/nestjs/src/outbound-campaigns/dto/create-campaign.dto.ts +47 -0
- package/nestjs/src/outbound-campaigns/dto/index.ts +3 -0
- package/nestjs/src/outbound-campaigns/dto/update-campaign.dto.ts +31 -0
- package/nestjs/src/outbound-campaigns/dto/upload-entries.dto.ts +35 -0
- package/nestjs/src/outbound-campaigns/outbound-campaigns.controller.ts +307 -0
- package/nestjs/src/outbound-campaigns/outbound-campaigns.module.ts +13 -0
- package/nestjs/src/outbound-campaigns/outbound-campaigns.service.ts +471 -0
- package/nestjs/src/outbound-campaigns/processors/campaign-dispatch.processor.ts +366 -0
- package/nestjs/src/patients/documents.service.ts +231 -0
- package/nestjs/src/patients/dto/create-examination.dto.ts +34 -0
- package/nestjs/src/patients/dto/create-note.dto.ts +14 -0
- package/nestjs/src/patients/dto/create-patient.dto.ts +86 -0
- package/nestjs/src/patients/dto/create-photo-set.dto.ts +32 -0
- package/nestjs/src/patients/dto/index.ts +10 -0
- package/nestjs/src/patients/dto/update-examination.dto.ts +29 -0
- package/nestjs/src/patients/dto/update-medical-history.dto.ts +47 -0
- package/nestjs/src/patients/dto/update-patient.dto.ts +87 -0
- package/nestjs/src/patients/dto/update-photo-set.dto.ts +28 -0
- package/nestjs/src/patients/dto/upload-document.dto.ts +31 -0
- package/nestjs/src/patients/dto/upload-photo.dto.ts +27 -0
- package/nestjs/src/patients/examinations.service.ts +271 -0
- package/nestjs/src/patients/medical-history.service.ts +149 -0
- package/nestjs/src/patients/notes.service.ts +172 -0
- package/nestjs/src/patients/patients.controller.ts +485 -0
- package/nestjs/src/patients/patients.module.ts +22 -0
- package/nestjs/src/patients/patients.service.ts +412 -0
- package/nestjs/src/patients/photo-sets.service.ts +389 -0
- package/nestjs/src/phone-numbers/dto/create-phone-number.dto.ts +57 -0
- package/nestjs/src/phone-numbers/dto/index.ts +3 -0
- package/nestjs/src/phone-numbers/dto/update-phone-number.dto.ts +38 -0
- package/nestjs/src/phone-numbers/dto/update-schedule.dto.ts +39 -0
- package/nestjs/src/phone-numbers/phone-numbers.controller.ts +125 -0
- package/nestjs/src/phone-numbers/phone-numbers.module.ts +10 -0
- package/nestjs/src/phone-numbers/phone-numbers.service.ts +209 -0
- package/nestjs/src/plans/dto/create-plan.dto.ts +70 -0
- package/nestjs/src/plans/dto/index.ts +2 -0
- package/nestjs/src/plans/dto/update-plan.dto.ts +80 -0
- package/nestjs/src/plans/plans.controller.ts +50 -0
- package/nestjs/src/plans/plans.module.ts +10 -0
- package/nestjs/src/plans/plans.service.ts +115 -0
- package/nestjs/src/platform/dto/create-tenant.dto.ts +36 -0
- package/nestjs/src/platform/dto/index.ts +2 -0
- package/nestjs/src/platform/dto/update-tenant-platform.dto.ts +44 -0
- package/nestjs/src/platform/platform.controller.ts +79 -0
- package/nestjs/src/platform/platform.module.ts +10 -0
- package/nestjs/src/platform/platform.service.ts +301 -0
- package/nestjs/src/queue/queue.module.ts +56 -0
- package/nestjs/src/redis/redis.module.ts +20 -0
- package/nestjs/src/tenants/dto/index.ts +1 -0
- package/nestjs/src/tenants/dto/update-tenant.dto.ts +15 -0
- package/nestjs/src/tenants/tenants.controller.ts +45 -0
- package/nestjs/src/tenants/tenants.module.ts +10 -0
- package/nestjs/src/tenants/tenants.service.ts +41 -0
- package/nestjs/src/tools/adapters/elevenlabs-http.adapter.ts +51 -0
- package/nestjs/src/tools/adapters/elevenlabs-ws.adapter.ts +59 -0
- package/nestjs/src/tools/handlers/calendar.tools.ts +441 -0
- package/nestjs/src/tools/handlers/notification.tools.ts +34 -0
- package/nestjs/src/tools/handlers/operator.tools.ts +303 -0
- package/nestjs/src/tools/handlers/patient.tools.ts +242 -0
- package/nestjs/src/tools/handlers/payment.tools.ts +43 -0
- package/nestjs/src/tools/handlers/validation.tools.ts +152 -0
- package/nestjs/src/tools/tool-registry.service.ts +221 -0
- package/nestjs/src/tools/tool.decorator.ts +16 -0
- package/nestjs/src/tools/tool.interfaces.ts +26 -0
- package/nestjs/src/tools/tools.module.ts +50 -0
- package/nestjs/src/treatments/dto/create-plan-item.dto.ts +27 -0
- package/nestjs/src/treatments/dto/create-treatment-plan.dto.ts +69 -0
- package/nestjs/src/treatments/dto/create-treatment.dto.ts +59 -0
- package/nestjs/src/treatments/dto/index.ts +6 -0
- package/nestjs/src/treatments/dto/update-plan-item.dto.ts +23 -0
- package/nestjs/src/treatments/dto/update-treatment-plan.dto.ts +22 -0
- package/nestjs/src/treatments/dto/update-treatment.dto.ts +70 -0
- package/nestjs/src/treatments/treatment-plans.service.ts +362 -0
- package/nestjs/src/treatments/treatments.controller.ts +265 -0
- package/nestjs/src/treatments/treatments.module.ts +14 -0
- package/nestjs/src/treatments/treatments.service.ts +165 -0
- package/nestjs/src/users/doctor-profiles.service.ts +202 -0
- package/nestjs/src/users/dto/index.ts +4 -0
- package/nestjs/src/users/dto/invite-user.dto.ts +52 -0
- package/nestjs/src/users/dto/update-clinic-assignments.dto.ts +9 -0
- package/nestjs/src/users/dto/update-doctor-profile.dto.ts +49 -0
- package/nestjs/src/users/dto/update-user.dto.ts +41 -0
- package/nestjs/src/users/users.controller.ts +142 -0
- package/nestjs/src/users/users.module.ts +11 -0
- package/nestjs/src/users/users.service.ts +250 -0
- package/nestjs/src/webhooks/elevenlabs-tool.controller.ts +66 -0
- package/nestjs/src/webhooks/elevenlabs-webhook.controller.ts +60 -0
- package/nestjs/src/webhooks/meta-webhook.controller.ts +178 -0
- package/nestjs/src/webhooks/processors/elevenlabs-webhook.processor.ts +28 -0
- package/nestjs/src/webhooks/webhooks.module.ts +17 -0
- package/nestjs/src/whatsapp/chat-context.service.ts +281 -0
- package/nestjs/src/whatsapp/dto/add-blacklist.dto.ts +13 -0
- package/nestjs/src/whatsapp/dto/index.ts +2 -0
- package/nestjs/src/whatsapp/dto/send-message.dto.ts +14 -0
- package/nestjs/src/whatsapp/listeners/meta-message.listener.ts +579 -0
- package/nestjs/src/whatsapp/meta-auth.controller.ts +268 -0
- package/nestjs/src/whatsapp/meta-instagram-auth.controller.ts +244 -0
- package/nestjs/src/whatsapp/operator.service.ts +692 -0
- package/nestjs/src/whatsapp/processors/cost-sweep.processor.ts +130 -0
- package/nestjs/src/whatsapp/processors/grace.processor.ts +191 -0
- package/nestjs/src/whatsapp/processors/message-buffer.processor.ts +138 -0
- package/nestjs/src/whatsapp/processors/message-cleanup.processor.ts +148 -0
- package/nestjs/src/whatsapp/processors/meta-token-refresh.processor.ts +114 -0
- package/nestjs/src/whatsapp/processors/operator-expiry.processor.ts +105 -0
- package/nestjs/src/whatsapp/processors/profile-update.processor.ts +234 -0
- package/nestjs/src/whatsapp/processors/session-cleanup.processor.ts +178 -0
- package/nestjs/src/whatsapp/processors/session-labels.processor.ts +248 -0
- package/nestjs/src/whatsapp/whatsapp-agent.service.ts +2506 -0
- package/nestjs/src/whatsapp/whatsapp-recovery.service.ts +117 -0
- package/nestjs/src/whatsapp/whatsapp.controller.ts +398 -0
- package/nestjs/src/whatsapp/whatsapp.module.ts +51 -0
- package/nestjs/src/whatsapp/whatsapp.service.ts +592 -0
- package/nestjs/test/app.e2e-spec.ts +25 -0
- package/nestjs/test/jest-e2e.json +9 -0
- package/nestjs/tsconfig.build.json +4 -0
- package/nestjs/tsconfig.json +25 -0
- package/nginx.example.conf +18 -0
- package/package.json +47 -0
- package/scripts/addRecipient.ts +48 -0
- package/scripts/listRecipients.ts +31 -0
- package/scripts/migrate-agent-ref.ts +86 -0
- package/scripts/migrate-sessions.ts +183 -0
- package/scripts/promote.ts +27 -0
- package/scripts/retrigger.ts +84 -0
- package/scripts/seed.ts +435 -0
- package/scripts/testSend.ts +63 -0
- package/src/app.ts +85 -0
- package/src/config/agentPrompts.json +19 -0
- package/src/config/database.ts +21 -0
- package/src/config/env.ts +94 -0
- package/src/config/index.ts +86 -0
- package/src/controllers/webhook.controller.ts +150 -0
- package/src/errors/index.ts +9 -0
- package/src/hooks/webhookValidator.ts +55 -0
- package/src/index.ts +68 -0
- package/src/migrations/001_session-architecture.ts +138 -0
- package/src/migrations/002_agent-ref.ts +65 -0
- package/src/migrations/003_shift-schedule.ts +55 -0
- package/src/migrations/004_invert-shift-to-clinic-hours.ts +30 -0
- package/src/migrations/005_composite-baileys-chat-ids.ts +60 -0
- package/src/migrations/migration.model.ts +27 -0
- package/src/migrations/migration.routes.ts +40 -0
- package/src/migrations/migration.runner.ts +112 -0
- package/src/models/ConversationClaim.ts +17 -0
- package/src/models/ConversationEvaluation.ts +91 -0
- package/src/models/Summary.ts +77 -0
- package/src/models/Transcription.ts +68 -0
- package/src/models/WhatsAppRecipient.ts +37 -0
- package/src/modules/admin/admin.routes.ts +2385 -0
- package/src/modules/admin/elevenlabs-test-chat.routes.ts +193 -0
- package/src/modules/admin/whatsapp-test-chat.routes.ts +244 -0
- package/src/modules/agents/agent.model.ts +93 -0
- package/src/modules/agents/agent.routes.ts +65 -0
- package/src/modules/appointment-validation/appointment-validation.model.ts +163 -0
- package/src/modules/appointment-validation/appointment-validation.routes.ts +275 -0
- package/src/modules/appointment-validation/appointment-validation.service.ts +1028 -0
- package/src/modules/auth/auth.model.ts +42 -0
- package/src/modules/auth/auth.routes.ts +199 -0
- package/src/modules/auth/auth.service.ts +210 -0
- package/src/modules/auth/refresh-token.model.ts +26 -0
- package/src/modules/billing/billing-alert.model.ts +28 -0
- package/src/modules/billing/billing-period-snapshot.model.ts +68 -0
- package/src/modules/billing/billing.model.ts +42 -0
- package/src/modules/billing/billing.routes.ts +67 -0
- package/src/modules/billing/billing.service.ts +562 -0
- package/src/modules/billing/payment.model.ts +42 -0
- package/src/modules/calls/call.model.ts +102 -0
- package/src/modules/calls/call.routes.ts +118 -0
- package/src/modules/campaigns/campaign.model.ts +111 -0
- package/src/modules/campaigns/campaign.routes.ts +402 -0
- package/src/modules/campaigns/campaign.service.ts +99 -0
- package/src/modules/google-calendar/google-calendar.routes.ts +31 -0
- package/src/modules/inbound-call/inbound-call-config.model.ts +49 -0
- package/src/modules/inbound-call/inbound-call.routes.ts +289 -0
- package/src/modules/leads/lead.model.ts +40 -0
- package/src/modules/leads/lead.routes.ts +246 -0
- package/src/modules/logs/log.model.ts +27 -0
- package/src/modules/logs/log.routes.ts +102 -0
- package/src/modules/plans/plan.model.ts +45 -0
- package/src/modules/surveys/survey.model.ts +70 -0
- package/src/modules/surveys/survey.routes.ts +187 -0
- package/src/modules/tenants/tenant.model.ts +181 -0
- package/src/modules/tenants/tenant.routes.ts +78 -0
- package/src/modules/users/user.routes.ts +126 -0
- package/src/modules/webhooks/elevenlabs-tool.routes.ts +94 -0
- package/src/modules/webhooks/elevenlabs-tool.service.ts +491 -0
- package/src/modules/webhooks/elevenlabs.routes.ts +34 -0
- package/src/modules/webhooks/elevenlabs.service.ts +565 -0
- package/src/modules/webhooks/unipile.routes.ts +917 -0
- package/src/modules/whatsapp/appointment.model.ts +47 -0
- package/src/modules/whatsapp/operator-request.model.ts +58 -0
- package/src/modules/whatsapp/stt-usage.model.ts +30 -0
- package/src/modules/whatsapp/whatsapp-chat.model.ts +39 -0
- package/src/modules/whatsapp/whatsapp-contact-profile.model.ts +41 -0
- package/src/modules/whatsapp/whatsapp-message.model.ts +41 -0
- package/src/modules/whatsapp/whatsapp-session.model.ts +60 -0
- package/src/modules/whatsapp/whatsapp.routes.ts +1435 -0
- package/src/plugins/cors.ts +7 -0
- package/src/plugins/jwt.ts +18 -0
- package/src/plugins/rawBody.ts +12 -0
- package/src/plugins/rbac.ts +24 -0
- package/src/routes/admin.routes.ts +208 -0
- package/src/routes/health.routes.ts +12 -0
- package/src/routes/webhook.routes.ts +12 -0
- package/src/services/ai/base.ai.ts +132 -0
- package/src/services/ai/gemini.service.ts +41 -0
- package/src/services/ai/index.ts +24 -0
- package/src/services/ai/openai.service.ts +48 -0
- package/src/services/elevenlabs.service.ts +532 -0
- package/src/services/google-calendar.service.ts +656 -0
- package/src/services/inbound-call-schedule.service.ts +174 -0
- package/src/services/netgsm.service.ts +128 -0
- package/src/services/unipile.service.ts +200 -0
- package/src/services/whatsapp-agent.service.ts +2479 -0
- package/src/services/whatsapp.service.ts +245 -0
- package/src/templates/index.ts +71 -0
- package/src/templates/receptionist.ts +44 -0
- package/src/templates/survey.ts +44 -0
- package/src/types/index.ts +218 -0
- package/src/utils/logger.ts +83 -0
- package/tsconfig.json +19 -0
- package/web/.dockerignore +4 -0
- package/web/Dockerfile +18 -0
- package/web/README.md +73 -0
- package/web/components.json +23 -0
- package/web/eslint.config.js +23 -0
- package/web/index.html +14 -0
- package/web/nginx.conf +18 -0
- package/web/package-lock.json +10292 -0
- package/web/package.json +48 -0
- package/web/public/favicon.ico +0 -0
- package/web/public/vite.svg +1 -0
- package/web/src/App.tsx +191 -0
- package/web/src/assets/react.svg +1 -0
- package/web/src/components/Layout.tsx +261 -0
- package/web/src/components/LeadConversation.tsx +251 -0
- package/web/src/components/ProtectedRoute.tsx +20 -0
- package/web/src/components/conversation-review/CardAudioPlayer.tsx +200 -0
- package/web/src/components/conversation-review/CardEvaluation.tsx +351 -0
- package/web/src/components/conversation-review/CardMetadata.tsx +44 -0
- package/web/src/components/conversation-review/ConversationCard.tsx +95 -0
- package/web/src/components/conversation-review/ReviewContainer.tsx +120 -0
- package/web/src/components/conversation-review/ReviewFilters.tsx +88 -0
- package/web/src/components/empty-state.tsx +15 -0
- package/web/src/components/page-header.tsx +19 -0
- package/web/src/components/page-loader.tsx +32 -0
- package/web/src/components/pagination.tsx +38 -0
- package/web/src/components/stat-card.tsx +27 -0
- package/web/src/components/status-badge.tsx +125 -0
- package/web/src/components/ui/alert.tsx +66 -0
- package/web/src/components/ui/badge.tsx +48 -0
- package/web/src/components/ui/button.tsx +64 -0
- package/web/src/components/ui/card.tsx +92 -0
- package/web/src/components/ui/checkbox.tsx +32 -0
- package/web/src/components/ui/dialog.tsx +158 -0
- package/web/src/components/ui/dropdown-menu.tsx +255 -0
- package/web/src/components/ui/input.tsx +21 -0
- package/web/src/components/ui/label.tsx +22 -0
- package/web/src/components/ui/progress.tsx +29 -0
- package/web/src/components/ui/select.tsx +188 -0
- package/web/src/components/ui/separator.tsx +28 -0
- package/web/src/components/ui/sheet.tsx +123 -0
- package/web/src/components/ui/skeleton.tsx +13 -0
- package/web/src/components/ui/sonner.tsx +35 -0
- package/web/src/components/ui/table.tsx +116 -0
- package/web/src/components/ui/tabs.tsx +89 -0
- package/web/src/components/ui/textarea.tsx +18 -0
- package/web/src/components/ui/tooltip.tsx +57 -0
- package/web/src/components/whatsapp/ChatDetail.tsx +417 -0
- package/web/src/components/whatsapp/ChatHeader.tsx +78 -0
- package/web/src/components/whatsapp/ChatList.tsx +107 -0
- package/web/src/components/whatsapp/ChatListItem.tsx +60 -0
- package/web/src/components/whatsapp/MessageBubble.tsx +46 -0
- package/web/src/components/whatsapp/MessageInput.tsx +63 -0
- package/web/src/components/whatsapp/MessageStream.tsx +135 -0
- package/web/src/components/whatsapp/SessionDivider.tsx +65 -0
- package/web/src/components/whatsapp/SessionHistory.tsx +119 -0
- package/web/src/components/whatsapp/settings/AiSettingsTab.tsx +268 -0
- package/web/src/components/whatsapp/settings/CalendarTab.tsx +339 -0
- package/web/src/components/whatsapp/settings/ConnectionTab.tsx +236 -0
- package/web/src/components/whatsapp/settings/NotificationsTab.tsx +109 -0
- package/web/src/components/whatsapp/settings/OperatorTab.tsx +303 -0
- package/web/src/contexts/AuthContext.tsx +103 -0
- package/web/src/index.css +130 -0
- package/web/src/lib/api.ts +92 -0
- package/web/src/lib/utils.ts +6 -0
- package/web/src/main.tsx +10 -0
- package/web/src/pages/AppointmentDetail.tsx +206 -0
- package/web/src/pages/AppointmentValidation.tsx +157 -0
- package/web/src/pages/AppointmentValidationDetail.tsx +617 -0
- package/web/src/pages/AppointmentValidationNew.tsx +1005 -0
- package/web/src/pages/Appointments.tsx +283 -0
- package/web/src/pages/Billing.tsx +126 -0
- package/web/src/pages/CallDetail.tsx +293 -0
- package/web/src/pages/CallSettings.tsx +313 -0
- package/web/src/pages/Calls.tsx +188 -0
- package/web/src/pages/CampaignDetail.tsx +216 -0
- package/web/src/pages/CampaignNew.tsx +277 -0
- package/web/src/pages/CampaignResults.tsx +185 -0
- package/web/src/pages/Campaigns.tsx +171 -0
- package/web/src/pages/Dashboard.tsx +336 -0
- package/web/src/pages/InboundSchedule.tsx +246 -0
- package/web/src/pages/LeadDetail.tsx +183 -0
- package/web/src/pages/Leads.tsx +258 -0
- package/web/src/pages/Login.tsx +99 -0
- package/web/src/pages/Register.tsx +129 -0
- package/web/src/pages/Settings.tsx +133 -0
- package/web/src/pages/SurveyDetail.tsx +232 -0
- package/web/src/pages/SurveyPreview.tsx +179 -0
- package/web/src/pages/Surveys.tsx +207 -0
- package/web/src/pages/Users.tsx +199 -0
- package/web/src/pages/WhatsApp.tsx +147 -0
- package/web/src/pages/WhatsAppSettings.tsx +215 -0
- package/web/src/pages/admin/AdminBaileysMessageLog.tsx +331 -0
- package/web/src/pages/admin/AdminBaileysRawMessages.tsx +318 -0
- package/web/src/pages/admin/AdminConversationReview.tsx +116 -0
- package/web/src/pages/admin/AdminCredits.tsx +467 -0
- package/web/src/pages/admin/AdminElevenLabsAgentDetail.tsx +332 -0
- package/web/src/pages/admin/AdminElevenLabsAgents.tsx +164 -0
- package/web/src/pages/admin/AdminElevenLabsBatchCallDetail.tsx +214 -0
- package/web/src/pages/admin/AdminElevenLabsBatchCalls.tsx +293 -0
- package/web/src/pages/admin/AdminElevenLabsConversationDetail.tsx +230 -0
- package/web/src/pages/admin/AdminElevenLabsConversations.tsx +228 -0
- package/web/src/pages/admin/AdminElevenLabsInboundCalls.tsx +293 -0
- package/web/src/pages/admin/AdminElevenLabsPhoneNumbers.tsx +506 -0
- package/web/src/pages/admin/AdminElevenLabsTestChat.tsx +258 -0
- package/web/src/pages/admin/AdminElevenLabsWebhooks.tsx +289 -0
- package/web/src/pages/admin/AdminEvaluationDashboard.tsx +520 -0
- package/web/src/pages/admin/AdminLeads.tsx +339 -0
- package/web/src/pages/admin/AdminLogs.tsx +283 -0
- package/web/src/pages/admin/AdminMigrations.tsx +247 -0
- package/web/src/pages/admin/AdminPlans.tsx +313 -0
- package/web/src/pages/admin/AdminSystem.tsx +391 -0
- package/web/src/pages/admin/AdminTenantBillableItems.tsx +464 -0
- package/web/src/pages/admin/AdminTenantDetail.tsx +1317 -0
- package/web/src/pages/admin/AdminTenants.tsx +274 -0
- package/web/src/pages/admin/AdminWhatsApp.tsx +618 -0
- package/web/src/pages/admin/AdminWhatsAppTestChat.tsx +328 -0
- package/web/src/types/index.ts +242 -0
- package/web/tsconfig.app.json +32 -0
- package/web/tsconfig.json +13 -0
- package/web/tsconfig.node.json +26 -0
- package/web/vite.config.ts +23 -0
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
import { useState } from "react"
|
|
2
|
+
import {
|
|
3
|
+
Bell,
|
|
4
|
+
Calendar,
|
|
5
|
+
ChevronDown,
|
|
6
|
+
CircleAlert,
|
|
7
|
+
ClipboardList,
|
|
8
|
+
Heart,
|
|
9
|
+
Loader2,
|
|
10
|
+
Mail,
|
|
11
|
+
MessageSquare,
|
|
12
|
+
Moon,
|
|
13
|
+
PanelLeftClose,
|
|
14
|
+
PanelLeftOpen,
|
|
15
|
+
Phone,
|
|
16
|
+
Plus,
|
|
17
|
+
Search,
|
|
18
|
+
Settings,
|
|
19
|
+
Sun,
|
|
20
|
+
Trash2,
|
|
21
|
+
TrendingUp,
|
|
22
|
+
User,
|
|
23
|
+
Stethoscope,
|
|
24
|
+
Camera,
|
|
25
|
+
CheckCircle,
|
|
26
|
+
XCircle,
|
|
27
|
+
AlertTriangle,
|
|
28
|
+
} from "lucide-react"
|
|
29
|
+
|
|
30
|
+
import { Button } from "@/components/ui/button"
|
|
31
|
+
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
|
|
32
|
+
import { Input } from "@/components/ui/input"
|
|
33
|
+
import { Label } from "@/components/ui/label"
|
|
34
|
+
import { Textarea } from "@/components/ui/textarea"
|
|
35
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
|
36
|
+
import { Checkbox } from "@/components/ui/checkbox"
|
|
37
|
+
import { Switch } from "@/components/ui/switch"
|
|
38
|
+
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
|
39
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
|
|
40
|
+
import { Separator } from "@/components/ui/separator"
|
|
41
|
+
import { Avatar, AvatarFallback } from "@/components/ui/avatar"
|
|
42
|
+
import { Badge } from "@/components/ui/badge"
|
|
43
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
|
44
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
|
45
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
|
|
46
|
+
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
|
47
|
+
import { Progress } from "@/components/ui/progress"
|
|
48
|
+
import { Skeleton } from "@/components/ui/skeleton"
|
|
49
|
+
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "@/components/ui/breadcrumb"
|
|
50
|
+
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
|
|
51
|
+
|
|
52
|
+
import {
|
|
53
|
+
PageHeader,
|
|
54
|
+
StatCard,
|
|
55
|
+
EmptyState,
|
|
56
|
+
StatusDot,
|
|
57
|
+
StatusBadge,
|
|
58
|
+
ConfirmDialog,
|
|
59
|
+
DataTableToolbar,
|
|
60
|
+
DataTablePagination,
|
|
61
|
+
AppointmentCalendar,
|
|
62
|
+
ChatBubble,
|
|
63
|
+
ActivityTimeline,
|
|
64
|
+
FileUpload,
|
|
65
|
+
NotificationDropdown,
|
|
66
|
+
Combobox,
|
|
67
|
+
} from "@/components/shared"
|
|
68
|
+
import type { TimelineItem, Notification as NotificationType } from "@/components/shared"
|
|
69
|
+
|
|
70
|
+
/* ─── Constants ────────────────────────────────────────── */
|
|
71
|
+
|
|
72
|
+
const sections = [
|
|
73
|
+
{ id: "buttons", label: "Buttons" },
|
|
74
|
+
{ id: "badges", label: "Badges & Status" },
|
|
75
|
+
{ id: "inputs", label: "Inputs & Forms" },
|
|
76
|
+
{ id: "cards", label: "Cards" },
|
|
77
|
+
{ id: "table", label: "Table" },
|
|
78
|
+
{ id: "tabs", label: "Tabs" },
|
|
79
|
+
{ id: "alerts", label: "Alerts & Progress" },
|
|
80
|
+
{ id: "dialog", label: "Dialog & Dropdown" },
|
|
81
|
+
{ id: "avatars", label: "Avatars & Tooltips" },
|
|
82
|
+
{ id: "skeleton", label: "Skeleton" },
|
|
83
|
+
{ id: "empty", label: "Empty State" },
|
|
84
|
+
{ id: "data-table", label: "Data Table Controls" },
|
|
85
|
+
{ id: "chat", label: "Chat Bubbles" },
|
|
86
|
+
{ id: "timeline", label: "Activity Timeline" },
|
|
87
|
+
{ id: "upload", label: "File Upload" },
|
|
88
|
+
{ id: "notifications", label: "Notifications" },
|
|
89
|
+
{ id: "combobox", label: "Combobox" },
|
|
90
|
+
{ id: "calendar", label: "Calendar" },
|
|
91
|
+
{ id: "confirm", label: "Confirm Dialog" },
|
|
92
|
+
] as const
|
|
93
|
+
|
|
94
|
+
const sampleTimeline: TimelineItem[] = [
|
|
95
|
+
{ id: "1", title: "Appointment completed", description: "Root canal — Dr. Mehmet", timestamp: new Date(2026, 3, 3, 10, 30), type: "success", icon: <CheckCircle className="w-3.5 h-3.5" /> },
|
|
96
|
+
{ id: "2", title: "AI session resolved", description: "Patient asked about implant pricing. Lead created.", timestamp: new Date(2026, 3, 3, 9, 15), type: "info", icon: <MessageSquare className="w-3.5 h-3.5" /> },
|
|
97
|
+
{ id: "3", title: "Photos uploaded", description: "Before set — 4 photos (front, left, right, smile)", timestamp: new Date(2026, 3, 2, 14, 0), type: "default", icon: <Camera className="w-3.5 h-3.5" /> },
|
|
98
|
+
{ id: "4", title: "Appointment cancelled", description: "Patient no-show for teeth whitening", timestamp: new Date(2026, 3, 1, 16, 0), type: "error", icon: <XCircle className="w-3.5 h-3.5" /> },
|
|
99
|
+
{ id: "5", title: "Treatment plan created", description: "Full Mouth Rehabilitation — 5 items", timestamp: new Date(2026, 2, 28, 11, 0), type: "warning", icon: <ClipboardList className="w-3.5 h-3.5" /> },
|
|
100
|
+
{ id: "6", title: "First contact via WhatsApp", description: "Patient inquired about dental cleaning", timestamp: new Date(2026, 2, 15, 8, 30), type: "info", icon: <Phone className="w-3.5 h-3.5" /> },
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
const sampleNotifications: NotificationType[] = [
|
|
104
|
+
{ id: "1", title: "New appointment booked", body: "Ayse Yilmaz booked root canal for Apr 8 at 09:00", type: "success", read: false, timestamp: new Date(2026, 3, 3, 10, 5) },
|
|
105
|
+
{ id: "2", title: "Operator request expired", body: "REF: R-AB2X — Doctor did not respond within 24h", type: "error", read: false, timestamp: new Date(2026, 3, 3, 9, 30) },
|
|
106
|
+
{ id: "3", title: "AI session active", body: "New WhatsApp conversation from +90 555 987 6543", type: "info", read: false, timestamp: new Date(2026, 3, 3, 9, 12) },
|
|
107
|
+
{ id: "4", title: "Billing alert", body: "Inbound call minutes at 90% of plan limit", type: "warning", read: true, timestamp: new Date(2026, 3, 2, 17, 0) },
|
|
108
|
+
{ id: "5", title: "Batch validation complete", body: "Monday Appointments — 18 confirmed, 2 rescheduled", type: "success", read: true, timestamp: new Date(2026, 3, 2, 14, 30) },
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
const patientOptions = [
|
|
112
|
+
{ value: "p1", label: "Ayse Yilmaz", description: "+90 555 123 4567", icon: <User className="w-4 h-4 text-muted-foreground" /> },
|
|
113
|
+
{ value: "p2", label: "Fatma Demir", description: "+90 555 234 5678", icon: <User className="w-4 h-4 text-muted-foreground" /> },
|
|
114
|
+
{ value: "p3", label: "Ahmet Kaya", description: "+90 555 345 6789", icon: <User className="w-4 h-4 text-muted-foreground" /> },
|
|
115
|
+
{ value: "p4", label: "Zeynep Ozturk", description: "+90 555 456 7890", icon: <User className="w-4 h-4 text-muted-foreground" /> },
|
|
116
|
+
{ value: "p5", label: "Murat Celik", description: "+90 555 567 8901", icon: <User className="w-4 h-4 text-muted-foreground" /> },
|
|
117
|
+
{ value: "p6", label: "Selin Yildiz", description: "+90 555 678 9012", icon: <User className="w-4 h-4 text-muted-foreground" /> },
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
/* ─── Helpers ──────────────────────────────────────────── */
|
|
121
|
+
|
|
122
|
+
function Section({ id, title, description, children }: { id: string; title: string; description?: string; children: React.ReactNode }) {
|
|
123
|
+
return (
|
|
124
|
+
<section id={id} className="scroll-mt-20 space-y-6">
|
|
125
|
+
<div>
|
|
126
|
+
<h2 className="text-xl font-semibold tracking-tight">{title}</h2>
|
|
127
|
+
{description && <p className="text-sm text-muted-foreground mt-1">{description}</p>}
|
|
128
|
+
</div>
|
|
129
|
+
{children}
|
|
130
|
+
</section>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* ─── App ──────────────────────────────────────────────── */
|
|
135
|
+
|
|
136
|
+
function App() {
|
|
137
|
+
const [darkMode, setDarkMode] = useState(false)
|
|
138
|
+
const [sidebarOpen, setSidebarOpen] = useState(true)
|
|
139
|
+
const [activeSection, setActiveSection] = useState("buttons")
|
|
140
|
+
const [progress, setProgress] = useState(65)
|
|
141
|
+
const [switchOn, setSwitchOn] = useState(true)
|
|
142
|
+
const [dialogOpen, setDialogOpen] = useState(false)
|
|
143
|
+
const [comboValue, setComboValue] = useState("")
|
|
144
|
+
const [notifications, setNotifications] = useState(sampleNotifications)
|
|
145
|
+
|
|
146
|
+
const toggleDark = () => {
|
|
147
|
+
setDarkMode(!darkMode)
|
|
148
|
+
document.documentElement.classList.toggle("dark")
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const scrollTo = (id: string) => {
|
|
152
|
+
setActiveSection(id)
|
|
153
|
+
document.getElementById(id)?.scrollIntoView({ behavior: "smooth" })
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<TooltipProvider>
|
|
158
|
+
<div className="min-h-screen bg-background text-foreground">
|
|
159
|
+
|
|
160
|
+
{/* ── Header ─────────────────────────────────── */}
|
|
161
|
+
<header className="sticky top-0 z-50 border-b border-border bg-background/80 backdrop-blur-md">
|
|
162
|
+
<div className="max-w-[1440px] mx-auto px-4 h-14 flex items-center justify-between">
|
|
163
|
+
<div className="flex items-center gap-3">
|
|
164
|
+
<Button variant="ghost" size="icon" onClick={() => setSidebarOpen(!sidebarOpen)} className="lg:flex">
|
|
165
|
+
{sidebarOpen ? <PanelLeftClose className="w-4 h-4" /> : <PanelLeftOpen className="w-4 h-4" />}
|
|
166
|
+
</Button>
|
|
167
|
+
<div className="w-8 h-8 rounded-lg bg-primary flex items-center justify-center shadow-sm">
|
|
168
|
+
<Heart className="w-4 h-4 text-primary-foreground" />
|
|
169
|
+
</div>
|
|
170
|
+
<span className="font-semibold tracking-tight hidden sm:inline">Portal Asistan 7/24</span>
|
|
171
|
+
<Badge variant="secondary" className="text-[10px] font-mono uppercase tracking-wider hidden sm:inline-flex">Design System</Badge>
|
|
172
|
+
</div>
|
|
173
|
+
<div className="flex items-center gap-2">
|
|
174
|
+
<NotificationDropdown
|
|
175
|
+
notifications={notifications}
|
|
176
|
+
onMarkRead={(id) => setNotifications(notifications.map((n) => n.id === id ? { ...n, read: true } : n))}
|
|
177
|
+
onMarkAllRead={() => setNotifications(notifications.map((n) => ({ ...n, read: true })))}
|
|
178
|
+
onClear={() => setNotifications([])}
|
|
179
|
+
/>
|
|
180
|
+
<Button variant="ghost" size="icon" onClick={toggleDark}>
|
|
181
|
+
{darkMode ? <Sun className="w-4 h-4" /> : <Moon className="w-4 h-4" />}
|
|
182
|
+
</Button>
|
|
183
|
+
<Avatar className="w-8 h-8">
|
|
184
|
+
<AvatarFallback className="bg-primary text-primary-foreground text-xs font-medium">TA</AvatarFallback>
|
|
185
|
+
</Avatar>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</header>
|
|
189
|
+
|
|
190
|
+
{/* ── Layout ─────────────────────────────────── */}
|
|
191
|
+
<div className="max-w-[1440px] mx-auto flex">
|
|
192
|
+
|
|
193
|
+
{/* ── Sidebar ───────────────────────────────── */}
|
|
194
|
+
<aside className={`${sidebarOpen ? "w-52" : "w-0"} shrink-0 sticky top-14 h-[calc(100vh-3.5rem)] border-r border-border overflow-hidden transition-all duration-200`}>
|
|
195
|
+
<div className="w-52 py-5 px-3 overflow-y-auto h-full">
|
|
196
|
+
<p className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest mb-2 px-2.5">Components</p>
|
|
197
|
+
<nav className="space-y-0.5">
|
|
198
|
+
{sections.map((s) => (
|
|
199
|
+
<button
|
|
200
|
+
key={s.id}
|
|
201
|
+
onClick={() => scrollTo(s.id)}
|
|
202
|
+
className={`w-full text-left px-2.5 py-1.5 rounded-md text-[13px] transition-colors ${activeSection === s.id ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:text-foreground hover:bg-muted"}`}
|
|
203
|
+
>
|
|
204
|
+
{s.label}
|
|
205
|
+
</button>
|
|
206
|
+
))}
|
|
207
|
+
</nav>
|
|
208
|
+
<Separator className="my-5" />
|
|
209
|
+
<div className="px-2.5 space-y-1.5">
|
|
210
|
+
<p className="text-[11px] text-muted-foreground">33 shadcn/ui + 14 custom</p>
|
|
211
|
+
<p className="text-[11px] text-muted-foreground">Tailwind CSS v4</p>
|
|
212
|
+
<p className="text-[11px] text-muted-foreground">React 19 + Compiler</p>
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
</aside>
|
|
216
|
+
|
|
217
|
+
{/* ── Content ───────────────────────────────── */}
|
|
218
|
+
<main className="flex-1 min-w-0 px-6 lg:px-10 py-8 space-y-14">
|
|
219
|
+
|
|
220
|
+
{/* Hero */}
|
|
221
|
+
<div>
|
|
222
|
+
<Breadcrumb>
|
|
223
|
+
<BreadcrumbList>
|
|
224
|
+
<BreadcrumbItem><BreadcrumbLink href="#">Dashboard</BreadcrumbLink></BreadcrumbItem>
|
|
225
|
+
<BreadcrumbSeparator />
|
|
226
|
+
<BreadcrumbItem><BreadcrumbPage>Design System</BreadcrumbPage></BreadcrumbItem>
|
|
227
|
+
</BreadcrumbList>
|
|
228
|
+
</Breadcrumb>
|
|
229
|
+
<div className="mt-3 space-y-1">
|
|
230
|
+
<h1 className="text-3xl font-bold tracking-tight">Component Showcase</h1>
|
|
231
|
+
<p className="text-muted-foreground">Every UI primitive themed with <span className="text-primary font-semibold">#e77d22</span> — 47 components ready for production.</p>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
{/* ── Buttons ─────────────────────────────── */}
|
|
236
|
+
<Section id="buttons" title="Buttons" description="Primary actions, secondary options, and icon triggers.">
|
|
237
|
+
<Card>
|
|
238
|
+
<CardContent className="pt-6 space-y-6">
|
|
239
|
+
<div>
|
|
240
|
+
<p className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest mb-3">Variants</p>
|
|
241
|
+
<div className="flex flex-wrap gap-2.5">
|
|
242
|
+
<Button>Primary</Button>
|
|
243
|
+
<Button variant="secondary">Secondary</Button>
|
|
244
|
+
<Button variant="destructive">Destructive</Button>
|
|
245
|
+
<Button variant="outline">Outline</Button>
|
|
246
|
+
<Button variant="ghost">Ghost</Button>
|
|
247
|
+
<Button variant="link">Link</Button>
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
<Separator />
|
|
251
|
+
<div>
|
|
252
|
+
<p className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest mb-3">Sizes & States</p>
|
|
253
|
+
<div className="flex flex-wrap items-center gap-2.5">
|
|
254
|
+
<Button size="xs">Extra Small</Button>
|
|
255
|
+
<Button size="sm">Small</Button>
|
|
256
|
+
<Button>Default</Button>
|
|
257
|
+
<Button size="lg">Large</Button>
|
|
258
|
+
<Button size="icon"><Plus className="w-4 h-4" /></Button>
|
|
259
|
+
<Button disabled>Disabled</Button>
|
|
260
|
+
<Button><Loader2 className="w-4 h-4 mr-1.5 animate-spin" />Loading</Button>
|
|
261
|
+
<Button><Mail className="w-4 h-4 mr-1.5" />With Icon</Button>
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
</CardContent>
|
|
265
|
+
</Card>
|
|
266
|
+
</Section>
|
|
267
|
+
|
|
268
|
+
{/* ── Badges & Status ─────────────────────── */}
|
|
269
|
+
<Section id="badges" title="Badges & Status" description="Status indicators for every entity in the system.">
|
|
270
|
+
<Card>
|
|
271
|
+
<CardContent className="pt-6 space-y-5">
|
|
272
|
+
<div>
|
|
273
|
+
<p className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest mb-3">shadcn Badges</p>
|
|
274
|
+
<div className="flex flex-wrap gap-2">
|
|
275
|
+
<Badge>Default</Badge>
|
|
276
|
+
<Badge variant="secondary">Secondary</Badge>
|
|
277
|
+
<Badge variant="destructive">Destructive</Badge>
|
|
278
|
+
<Badge variant="outline">Outline</Badge>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
<Separator />
|
|
282
|
+
<div>
|
|
283
|
+
<p className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest mb-3">Appointment Statuses</p>
|
|
284
|
+
<div className="flex flex-wrap gap-2">
|
|
285
|
+
{["scheduled", "confirmed", "in_progress", "completed", "cancelled", "no_show"].map((s) => <StatusBadge key={s} status={s} />)}
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
288
|
+
<div>
|
|
289
|
+
<p className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest mb-3">Sessions, Leads, Campaigns, Calls</p>
|
|
290
|
+
<div className="flex flex-wrap gap-2">
|
|
291
|
+
{["active", "waiting", "resolved", "new_lead", "contacted", "draft", "running", "paused", "pending", "responded", "expired", "failed", "no_answer", "voicemail"].map((s) => <StatusBadge key={s} status={s} />)}
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
<Separator />
|
|
295
|
+
<div>
|
|
296
|
+
<p className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest mb-3">Status Dots</p>
|
|
297
|
+
<div className="flex flex-wrap gap-6">
|
|
298
|
+
<StatusDot status="active" label="Active" pulse />
|
|
299
|
+
<StatusDot status="waiting" label="Waiting" pulse />
|
|
300
|
+
<StatusDot status="offline" label="Offline" />
|
|
301
|
+
<StatusDot status="busy" label="Busy" />
|
|
302
|
+
<StatusDot status="completed" label="Done" />
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
</CardContent>
|
|
306
|
+
</Card>
|
|
307
|
+
</Section>
|
|
308
|
+
|
|
309
|
+
{/* ── Inputs & Forms ──────────────────────── */}
|
|
310
|
+
<Section id="inputs" title="Inputs & Forms" description="Text fields, selects, checkboxes, switches, and radio groups.">
|
|
311
|
+
<Card>
|
|
312
|
+
<CardContent className="pt-6 space-y-6">
|
|
313
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
|
|
314
|
+
<div className="space-y-1.5">
|
|
315
|
+
<Label htmlFor="inp-name">Patient Name</Label>
|
|
316
|
+
<Input id="inp-name" placeholder="Ayse Yilmaz" />
|
|
317
|
+
</div>
|
|
318
|
+
<div className="space-y-1.5">
|
|
319
|
+
<Label htmlFor="inp-phone">Phone</Label>
|
|
320
|
+
<Input id="inp-phone" type="tel" placeholder="+90 555 123 4567" />
|
|
321
|
+
</div>
|
|
322
|
+
<div className="space-y-1.5">
|
|
323
|
+
<Label htmlFor="inp-search">Search</Label>
|
|
324
|
+
<div className="relative">
|
|
325
|
+
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
|
|
326
|
+
<Input id="inp-search" className="pl-9" placeholder="Search patients..." />
|
|
327
|
+
</div>
|
|
328
|
+
</div>
|
|
329
|
+
<div className="space-y-1.5">
|
|
330
|
+
<Label>Clinic Branch</Label>
|
|
331
|
+
<Select>
|
|
332
|
+
<SelectTrigger><SelectValue placeholder="Select clinic" /></SelectTrigger>
|
|
333
|
+
<SelectContent>
|
|
334
|
+
<SelectItem value="kadikoy">Kadikoy</SelectItem>
|
|
335
|
+
<SelectItem value="besiktas">Besiktas</SelectItem>
|
|
336
|
+
<SelectItem value="atasehir">Atasehir</SelectItem>
|
|
337
|
+
</SelectContent>
|
|
338
|
+
</Select>
|
|
339
|
+
</div>
|
|
340
|
+
<div className="space-y-1.5 md:col-span-2">
|
|
341
|
+
<Label htmlFor="inp-notes">Clinical Notes</Label>
|
|
342
|
+
<Textarea id="inp-notes" placeholder="Enter examination findings..." rows={3} />
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
<Separator />
|
|
346
|
+
<div className="flex flex-wrap gap-8">
|
|
347
|
+
<div className="flex items-center gap-2">
|
|
348
|
+
<Checkbox id="cb-consent" />
|
|
349
|
+
<Label htmlFor="cb-consent" className="text-sm">KVKK consent</Label>
|
|
350
|
+
</div>
|
|
351
|
+
<div className="flex items-center gap-2">
|
|
352
|
+
<Switch checked={switchOn} onCheckedChange={setSwitchOn} />
|
|
353
|
+
<Label className="text-sm">AI Agent {switchOn ? "Active" : "Inactive"}</Label>
|
|
354
|
+
</div>
|
|
355
|
+
</div>
|
|
356
|
+
<Separator />
|
|
357
|
+
<div>
|
|
358
|
+
<p className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest mb-3">Radio Group</p>
|
|
359
|
+
<RadioGroup defaultValue="whatsapp" className="flex gap-4">
|
|
360
|
+
{[["whatsapp", "WhatsApp"], ["voice", "Voice Call"], ["instagram", "Instagram"]].map(([v, l]) => (
|
|
361
|
+
<div key={v} className="flex items-center gap-2">
|
|
362
|
+
<RadioGroupItem value={v} id={`rg-${v}`} />
|
|
363
|
+
<Label htmlFor={`rg-${v}`} className="text-sm">{l}</Label>
|
|
364
|
+
</div>
|
|
365
|
+
))}
|
|
366
|
+
</RadioGroup>
|
|
367
|
+
</div>
|
|
368
|
+
</CardContent>
|
|
369
|
+
</Card>
|
|
370
|
+
</Section>
|
|
371
|
+
|
|
372
|
+
{/* ── Cards ───────────────────────────────── */}
|
|
373
|
+
<Section id="cards" title="Cards" description="KPI stat cards and content cards.">
|
|
374
|
+
<PageHeader title="Dashboard" description="Overview of today's clinic activity">
|
|
375
|
+
<Button variant="outline" size="sm"><Settings className="w-4 h-4 mr-1.5" />Settings</Button>
|
|
376
|
+
</PageHeader>
|
|
377
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
378
|
+
<StatCard title="Total Patients" value="1,284" icon={<User className="w-4 h-4" />} trend={{ value: "12%", positive: true }} description="from last month" />
|
|
379
|
+
<StatCard title="Appointments" value={18} icon={<Calendar className="w-4 h-4" />} description="3 done, 15 upcoming" />
|
|
380
|
+
<StatCard title="AI Sessions" value={5} icon={<MessageSquare className="w-4 h-4" />} trend={{ value: "2", positive: true }} description="vs yesterday" />
|
|
381
|
+
<StatCard title="Open Leads" value={23} icon={<TrendingUp className="w-4 h-4" />} trend={{ value: "8%", positive: false }} description="from last week" />
|
|
382
|
+
</div>
|
|
383
|
+
<Card>
|
|
384
|
+
<CardHeader>
|
|
385
|
+
<CardTitle>Patient Profile</CardTitle>
|
|
386
|
+
<CardDescription>View and manage patient information</CardDescription>
|
|
387
|
+
</CardHeader>
|
|
388
|
+
<CardContent className="space-y-4">
|
|
389
|
+
<div className="flex items-center gap-4">
|
|
390
|
+
<Avatar className="w-14 h-14">
|
|
391
|
+
<AvatarFallback className="bg-primary/10 text-primary text-lg font-semibold">AY</AvatarFallback>
|
|
392
|
+
</Avatar>
|
|
393
|
+
<div>
|
|
394
|
+
<p className="font-semibold">Ayse Yilmaz</p>
|
|
395
|
+
<p className="text-sm text-muted-foreground">+90 555 123 4567</p>
|
|
396
|
+
<div className="flex gap-1.5 mt-1">
|
|
397
|
+
<Badge variant="outline" className="text-[10px]">VIP</Badge>
|
|
398
|
+
<Badge variant="outline" className="text-[10px]">Dental</Badge>
|
|
399
|
+
<StatusBadge status="active" className="text-[10px]" />
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
<Separator />
|
|
404
|
+
<div className="grid grid-cols-3 gap-4 text-sm">
|
|
405
|
+
<div><span className="text-muted-foreground text-xs">Last Visit</span><p className="font-medium">Mar 15, 2026</p></div>
|
|
406
|
+
<div><span className="text-muted-foreground text-xs">Treatment</span><p className="font-medium">Full Mouth Rehab</p></div>
|
|
407
|
+
<div><span className="text-muted-foreground text-xs">Next Appt</span><p className="font-medium">Apr 8, 09:00</p></div>
|
|
408
|
+
</div>
|
|
409
|
+
</CardContent>
|
|
410
|
+
<CardFooter className="flex gap-2">
|
|
411
|
+
<Button size="sm">View Profile</Button>
|
|
412
|
+
<Button size="sm" variant="outline">Book Appointment</Button>
|
|
413
|
+
</CardFooter>
|
|
414
|
+
</Card>
|
|
415
|
+
</Section>
|
|
416
|
+
|
|
417
|
+
{/* ── Table ───────────────────────────────── */}
|
|
418
|
+
<Section id="table" title="Table" description="Data grids for appointments, patients, calls, and leads.">
|
|
419
|
+
<Card>
|
|
420
|
+
<CardContent className="pt-6">
|
|
421
|
+
<Table>
|
|
422
|
+
<TableHeader>
|
|
423
|
+
<TableRow>
|
|
424
|
+
<TableHead>Patient</TableHead>
|
|
425
|
+
<TableHead>Treatment</TableHead>
|
|
426
|
+
<TableHead>Doctor</TableHead>
|
|
427
|
+
<TableHead>Time</TableHead>
|
|
428
|
+
<TableHead>Status</TableHead>
|
|
429
|
+
</TableRow>
|
|
430
|
+
</TableHeader>
|
|
431
|
+
<TableBody>
|
|
432
|
+
{[
|
|
433
|
+
{ name: "Ayse Yilmaz", tx: "Root Canal", doc: "Dr. Mehmet", time: "09:00", st: "completed" },
|
|
434
|
+
{ name: "Fatma Demir", tx: "Implant Consult", doc: "Dr. Elif", time: "10:30", st: "in_progress" },
|
|
435
|
+
{ name: "Ahmet Kaya", tx: "Whitening", doc: "Dr. Mehmet", time: "14:00", st: "scheduled" },
|
|
436
|
+
{ name: "Zeynep Ozturk", tx: "Botox", doc: "Dr. Elif", time: "15:30", st: "confirmed" },
|
|
437
|
+
{ name: "Murat Celik", tx: "Cleaning", doc: "Dr. Mehmet", time: "16:00", st: "no_show" },
|
|
438
|
+
].map((r) => (
|
|
439
|
+
<TableRow key={r.name}>
|
|
440
|
+
<TableCell className="font-medium">{r.name}</TableCell>
|
|
441
|
+
<TableCell>{r.tx}</TableCell>
|
|
442
|
+
<TableCell>{r.doc}</TableCell>
|
|
443
|
+
<TableCell className="tabular-nums">{r.time}</TableCell>
|
|
444
|
+
<TableCell><StatusBadge status={r.st} /></TableCell>
|
|
445
|
+
</TableRow>
|
|
446
|
+
))}
|
|
447
|
+
</TableBody>
|
|
448
|
+
</Table>
|
|
449
|
+
</CardContent>
|
|
450
|
+
</Card>
|
|
451
|
+
</Section>
|
|
452
|
+
|
|
453
|
+
{/* ── Tabs ────────────────────────────────── */}
|
|
454
|
+
<Section id="tabs" title="Tabs" description="Content sections for patient detail pages.">
|
|
455
|
+
<Tabs defaultValue="overview">
|
|
456
|
+
<TabsList>
|
|
457
|
+
{["Overview", "Appointments", "Treatment Plan", "Before / After", "Documents"].map((t) => (
|
|
458
|
+
<TabsTrigger key={t} value={t.toLowerCase().replace(/ \/ /g, "-").replace(/ /g, "-")}>{t}</TabsTrigger>
|
|
459
|
+
))}
|
|
460
|
+
</TabsList>
|
|
461
|
+
{["overview", "appointments", "treatment-plan", "before-after", "documents"].map((v) => (
|
|
462
|
+
<TabsContent key={v} value={v} className="mt-4">
|
|
463
|
+
<Card><CardContent className="pt-6"><p className="text-sm text-muted-foreground">Content for {v.replace(/-/g, " ")} tab.</p></CardContent></Card>
|
|
464
|
+
</TabsContent>
|
|
465
|
+
))}
|
|
466
|
+
</Tabs>
|
|
467
|
+
</Section>
|
|
468
|
+
|
|
469
|
+
{/* ── Alerts & Progress ────────────────────── */}
|
|
470
|
+
<Section id="alerts" title="Alerts & Progress" description="Notifications, warnings, and progress indicators.">
|
|
471
|
+
<div className="space-y-3">
|
|
472
|
+
<Alert>
|
|
473
|
+
<AlertTriangle className="w-4 h-4" />
|
|
474
|
+
<AlertTitle>Anamnesis Incomplete</AlertTitle>
|
|
475
|
+
<AlertDescription>Patient Ayse Yilmaz has not completed the medical history form.</AlertDescription>
|
|
476
|
+
</Alert>
|
|
477
|
+
<Alert variant="destructive">
|
|
478
|
+
<CircleAlert className="w-4 h-4" />
|
|
479
|
+
<AlertTitle>Operator Request Expired</AlertTitle>
|
|
480
|
+
<AlertDescription>REF: R-AB2X — Doctor did not respond within 24 hours.</AlertDescription>
|
|
481
|
+
</Alert>
|
|
482
|
+
</div>
|
|
483
|
+
<Card>
|
|
484
|
+
<CardContent className="pt-6 space-y-4">
|
|
485
|
+
<div className="space-y-2 max-w-md">
|
|
486
|
+
<div className="flex justify-between text-sm">
|
|
487
|
+
<span>Treatment Plan Progress</span>
|
|
488
|
+
<span className="text-muted-foreground tabular-nums">{progress}%</span>
|
|
489
|
+
</div>
|
|
490
|
+
<Progress value={progress} />
|
|
491
|
+
</div>
|
|
492
|
+
<div className="flex gap-2">
|
|
493
|
+
<Button size="xs" variant="outline" onClick={() => setProgress(Math.max(0, progress - 15))}>-15%</Button>
|
|
494
|
+
<Button size="xs" variant="outline" onClick={() => setProgress(Math.min(100, progress + 15))}>+15%</Button>
|
|
495
|
+
</div>
|
|
496
|
+
</CardContent>
|
|
497
|
+
</Card>
|
|
498
|
+
</Section>
|
|
499
|
+
|
|
500
|
+
{/* ── Dialog & Dropdown ────────────────────── */}
|
|
501
|
+
<Section id="dialog" title="Dialog & Dropdown" description="Modal forms and context menus.">
|
|
502
|
+
<div className="flex flex-wrap gap-3">
|
|
503
|
+
<Button onClick={() => setDialogOpen(true)}><Plus className="w-4 h-4 mr-1.5" />New Appointment</Button>
|
|
504
|
+
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
|
505
|
+
<DialogContent>
|
|
506
|
+
<DialogHeader>
|
|
507
|
+
<DialogTitle>Book Appointment</DialogTitle>
|
|
508
|
+
<DialogDescription>Schedule a new appointment for the patient.</DialogDescription>
|
|
509
|
+
</DialogHeader>
|
|
510
|
+
<div className="space-y-4 py-2">
|
|
511
|
+
<div className="space-y-1.5"><Label>Patient</Label><Input placeholder="Search patient..." /></div>
|
|
512
|
+
<div className="grid grid-cols-2 gap-4">
|
|
513
|
+
<div className="space-y-1.5"><Label>Date</Label><Input type="date" /></div>
|
|
514
|
+
<div className="space-y-1.5"><Label>Time</Label><Input type="time" /></div>
|
|
515
|
+
</div>
|
|
516
|
+
<div className="space-y-1.5">
|
|
517
|
+
<Label>Treatment</Label>
|
|
518
|
+
<Select><SelectTrigger><SelectValue placeholder="Select treatment" /></SelectTrigger>
|
|
519
|
+
<SelectContent>
|
|
520
|
+
<SelectItem value="cleaning">Cleaning</SelectItem>
|
|
521
|
+
<SelectItem value="rootcanal">Root Canal</SelectItem>
|
|
522
|
+
<SelectItem value="implant">Implant</SelectItem>
|
|
523
|
+
</SelectContent>
|
|
524
|
+
</Select>
|
|
525
|
+
</div>
|
|
526
|
+
</div>
|
|
527
|
+
<DialogFooter>
|
|
528
|
+
<Button variant="outline" onClick={() => setDialogOpen(false)}>Cancel</Button>
|
|
529
|
+
<Button onClick={() => setDialogOpen(false)}>Book</Button>
|
|
530
|
+
</DialogFooter>
|
|
531
|
+
</DialogContent>
|
|
532
|
+
</Dialog>
|
|
533
|
+
|
|
534
|
+
<DropdownMenu>
|
|
535
|
+
<DropdownMenuTrigger className="inline-flex items-center gap-1.5 rounded-lg border border-input bg-input-background px-2.5 h-8 text-sm font-medium shadow-xs hover:bg-muted cursor-pointer">
|
|
536
|
+
<Settings className="w-4 h-4" /> Actions <ChevronDown className="w-3.5 h-3.5 text-muted-foreground" />
|
|
537
|
+
</DropdownMenuTrigger>
|
|
538
|
+
<DropdownMenuContent align="start">
|
|
539
|
+
<DropdownMenuGroup>
|
|
540
|
+
<DropdownMenuLabel>Patient Actions</DropdownMenuLabel>
|
|
541
|
+
<DropdownMenuItem><User className="w-4 h-4 mr-2" />View Profile</DropdownMenuItem>
|
|
542
|
+
<DropdownMenuItem><Calendar className="w-4 h-4 mr-2" />Book Appointment</DropdownMenuItem>
|
|
543
|
+
<DropdownMenuItem><MessageSquare className="w-4 h-4 mr-2" />Send Message</DropdownMenuItem>
|
|
544
|
+
</DropdownMenuGroup>
|
|
545
|
+
<DropdownMenuSeparator />
|
|
546
|
+
<DropdownMenuItem className="text-destructive"><Trash2 className="w-4 h-4 mr-2" />Delete</DropdownMenuItem>
|
|
547
|
+
</DropdownMenuContent>
|
|
548
|
+
</DropdownMenu>
|
|
549
|
+
</div>
|
|
550
|
+
</Section>
|
|
551
|
+
|
|
552
|
+
{/* ── Avatars & Tooltips ───────────────────── */}
|
|
553
|
+
<Section id="avatars" title="Avatars & Tooltips" description="User avatars with tooltip details.">
|
|
554
|
+
<Card>
|
|
555
|
+
<CardContent className="pt-6 flex items-center gap-6 flex-wrap">
|
|
556
|
+
<div>
|
|
557
|
+
<p className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest mb-3">Doctors</p>
|
|
558
|
+
<div className="flex -space-x-2">
|
|
559
|
+
{[{ i: "M", c: "bg-primary/10 text-primary", n: "Mehmet" }, { i: "E", c: "bg-blue-500/10 text-blue-600", n: "Elif" }, { i: "A", c: "bg-purple-500/10 text-purple-600", n: "Ayse" }].map((d) => (
|
|
560
|
+
<Tooltip key={d.i}>
|
|
561
|
+
<TooltipTrigger className="cursor-default">
|
|
562
|
+
<Avatar className="w-10 h-10 border-2 border-background"><AvatarFallback className={`${d.c} text-sm font-medium`}>{d.i}</AvatarFallback></Avatar>
|
|
563
|
+
</TooltipTrigger>
|
|
564
|
+
<TooltipContent>Dr. {d.n}</TooltipContent>
|
|
565
|
+
</Tooltip>
|
|
566
|
+
))}
|
|
567
|
+
</div>
|
|
568
|
+
</div>
|
|
569
|
+
<Separator orientation="vertical" className="h-12" />
|
|
570
|
+
<div>
|
|
571
|
+
<p className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest mb-3">Icons</p>
|
|
572
|
+
<div className="flex gap-2">
|
|
573
|
+
{[{ icon: <Bell className="w-4 h-4" />, tip: "Notifications" }, { icon: <Phone className="w-4 h-4" />, tip: "Call" }, { icon: <Stethoscope className="w-4 h-4" />, tip: "Examination" }].map((t) => (
|
|
574
|
+
<Tooltip key={t.tip}>
|
|
575
|
+
<TooltipTrigger className="inline-flex items-center justify-center rounded-lg border border-input bg-input-background h-9 w-9 shadow-xs hover:bg-muted cursor-pointer">{t.icon}</TooltipTrigger>
|
|
576
|
+
<TooltipContent>{t.tip}</TooltipContent>
|
|
577
|
+
</Tooltip>
|
|
578
|
+
))}
|
|
579
|
+
</div>
|
|
580
|
+
</div>
|
|
581
|
+
</CardContent>
|
|
582
|
+
</Card>
|
|
583
|
+
</Section>
|
|
584
|
+
|
|
585
|
+
{/* ── Skeleton ────────────────────────────── */}
|
|
586
|
+
<Section id="skeleton" title="Skeleton" description="Loading placeholders for async content.">
|
|
587
|
+
<Card>
|
|
588
|
+
<CardContent className="pt-6 space-y-6">
|
|
589
|
+
<div className="flex items-center gap-4">
|
|
590
|
+
<Skeleton className="w-12 h-12 rounded-full" />
|
|
591
|
+
<div className="space-y-2 flex-1"><Skeleton className="h-4 w-48" /><Skeleton className="h-3 w-32" /></div>
|
|
592
|
+
<Skeleton className="h-8 w-24 rounded-lg" />
|
|
593
|
+
</div>
|
|
594
|
+
<div className="space-y-2">
|
|
595
|
+
<Skeleton className="h-3 w-full" /><Skeleton className="h-3 w-4/5" /><Skeleton className="h-3 w-3/5" />
|
|
596
|
+
</div>
|
|
597
|
+
</CardContent>
|
|
598
|
+
</Card>
|
|
599
|
+
</Section>
|
|
600
|
+
|
|
601
|
+
{/* ── Empty State ─────────────────────────── */}
|
|
602
|
+
<Section id="empty" title="Empty State" description="Friendly message when no data exists.">
|
|
603
|
+
<Card>
|
|
604
|
+
<EmptyState
|
|
605
|
+
icon={<Calendar className="w-6 h-6" />}
|
|
606
|
+
title="No appointments today"
|
|
607
|
+
description="There are no scheduled appointments for today. Book a new one or check another date."
|
|
608
|
+
action={<Button size="sm"><Plus className="w-4 h-4 mr-1.5" />Book Appointment</Button>}
|
|
609
|
+
/>
|
|
610
|
+
</Card>
|
|
611
|
+
</Section>
|
|
612
|
+
|
|
613
|
+
{/* ── Data Table Controls ──────────────────── */}
|
|
614
|
+
<Section id="data-table" title="Data Table Controls" description="Toolbar with search/filters and pagination.">
|
|
615
|
+
<Card>
|
|
616
|
+
<CardContent className="pt-6 space-y-4">
|
|
617
|
+
<DataTableToolbar
|
|
618
|
+
searchPlaceholder="Search patients..."
|
|
619
|
+
filters={
|
|
620
|
+
<Select><SelectTrigger className="w-[150px]"><SelectValue placeholder="All clinics" /></SelectTrigger>
|
|
621
|
+
<SelectContent><SelectItem value="all">All Clinics</SelectItem><SelectItem value="kadikoy">Kadikoy</SelectItem></SelectContent>
|
|
622
|
+
</Select>
|
|
623
|
+
}
|
|
624
|
+
actions={<Button size="sm"><Plus className="w-4 h-4 mr-1.5" />Add</Button>}
|
|
625
|
+
/>
|
|
626
|
+
<Separator />
|
|
627
|
+
<DataTablePagination page={2} pageSize={20} totalItems={284} onPageChange={() => {}} onPageSizeChange={() => {}} />
|
|
628
|
+
</CardContent>
|
|
629
|
+
</Card>
|
|
630
|
+
</Section>
|
|
631
|
+
|
|
632
|
+
{/* ── Chat Bubbles ─────────────────────────── */}
|
|
633
|
+
<Section id="chat" title="Chat Bubbles" description="WhatsApp-style message display for live chat.">
|
|
634
|
+
<Card>
|
|
635
|
+
<CardContent className="pt-6 space-y-3 max-w-lg mx-auto">
|
|
636
|
+
<ChatBubble sender="system" text="Session started — AI agent activated" timestamp={new Date(2026, 3, 3, 9, 0)} />
|
|
637
|
+
<ChatBubble sender="contact" senderName="Ayse" text="Merhaba, dis temizligi icin randevu almak istiyorum." timestamp={new Date(2026, 3, 3, 9, 1)} />
|
|
638
|
+
<ChatBubble sender="ai" text="Merhaba Ayse Hanim! Dis temizligi icin musait zamanlari kontrol ediyorum. Hangi gun uygun olur sizin icin?" timestamp={new Date(2026, 3, 3, 9, 1)} />
|
|
639
|
+
<ChatBubble sender="contact" senderName="Ayse" text="Bu cuma olabilir mi?" timestamp={new Date(2026, 3, 3, 9, 2)} />
|
|
640
|
+
<ChatBubble sender="ai" text="Cuma gunu 10:00 ve 14:30 saatlerinde musaitlik var. Hangisini tercih edersiniz?" timestamp={new Date(2026, 3, 3, 9, 2)} />
|
|
641
|
+
<ChatBubble sender="contact" senderName="Ayse" text="10:00 olsun lutfen" timestamp={new Date(2026, 3, 3, 9, 3)} />
|
|
642
|
+
<ChatBubble sender="human" senderName="Receptionist" text="Randevunuz onaylandi. Cuma 10:00'da bekliyoruz!" timestamp={new Date(2026, 3, 3, 9, 5)} />
|
|
643
|
+
<ChatBubble sender="contact" senderName="Ayse" text="Tesekkurler!" mediaType="imageMessage" timestamp={new Date(2026, 3, 3, 9, 6)} />
|
|
644
|
+
</CardContent>
|
|
645
|
+
</Card>
|
|
646
|
+
</Section>
|
|
647
|
+
|
|
648
|
+
{/* ── Activity Timeline ────────────────────── */}
|
|
649
|
+
<Section id="timeline" title="Activity Timeline" description="Chronological activity feed for patient detail pages.">
|
|
650
|
+
<Card>
|
|
651
|
+
<CardContent className="pt-6">
|
|
652
|
+
<ActivityTimeline items={sampleTimeline} />
|
|
653
|
+
</CardContent>
|
|
654
|
+
</Card>
|
|
655
|
+
</Section>
|
|
656
|
+
|
|
657
|
+
{/* ── File Upload ──────────────────────────── */}
|
|
658
|
+
<Section id="upload" title="File Upload" description="Drag-and-drop file upload for documents and photos.">
|
|
659
|
+
<Card>
|
|
660
|
+
<CardContent className="pt-6">
|
|
661
|
+
<div className="max-w-md mx-auto">
|
|
662
|
+
<FileUpload
|
|
663
|
+
accept="image/*,.pdf"
|
|
664
|
+
multiple
|
|
665
|
+
maxFiles={5}
|
|
666
|
+
maxSizeMB={10}
|
|
667
|
+
label="Upload patient documents"
|
|
668
|
+
description="Images and PDFs up to 10MB each. Max 5 files."
|
|
669
|
+
onFilesChange={() => {}}
|
|
670
|
+
/>
|
|
671
|
+
</div>
|
|
672
|
+
</CardContent>
|
|
673
|
+
</Card>
|
|
674
|
+
</Section>
|
|
675
|
+
|
|
676
|
+
{/* ── Notifications ────────────────────────── */}
|
|
677
|
+
<Section id="notifications" title="Notifications" description="Real-time notification dropdown with unread tracking.">
|
|
678
|
+
<Card>
|
|
679
|
+
<CardContent className="pt-6">
|
|
680
|
+
<p className="text-sm text-muted-foreground mb-3">The notification bell in the header above is live — click it to see the dropdown. It shows {notifications.filter((n) => !n.read).length} unread notifications.</p>
|
|
681
|
+
<div className="flex gap-3">
|
|
682
|
+
<Button size="sm" variant="outline" onClick={() => setNotifications(sampleNotifications)}>Reset Notifications</Button>
|
|
683
|
+
<Button size="sm" variant="outline" onClick={() => setNotifications([...notifications, { id: String(Date.now()), title: "New lead created", body: "Patient from WhatsApp ad — interested in implants", type: "info" as const, read: false, timestamp: new Date() }])}>
|
|
684
|
+
<Plus className="w-4 h-4 mr-1.5" />Add Notification
|
|
685
|
+
</Button>
|
|
686
|
+
</div>
|
|
687
|
+
</CardContent>
|
|
688
|
+
</Card>
|
|
689
|
+
</Section>
|
|
690
|
+
|
|
691
|
+
{/* ── Combobox ─────────────────────────────── */}
|
|
692
|
+
<Section id="combobox" title="Combobox" description="Searchable select for patients, doctors, and treatments.">
|
|
693
|
+
<Card>
|
|
694
|
+
<CardContent className="pt-6">
|
|
695
|
+
<div className="max-w-sm space-y-1.5">
|
|
696
|
+
<Label>Select Patient</Label>
|
|
697
|
+
<Combobox
|
|
698
|
+
options={patientOptions}
|
|
699
|
+
value={comboValue}
|
|
700
|
+
onSelect={setComboValue}
|
|
701
|
+
placeholder="Search patients..."
|
|
702
|
+
searchPlaceholder="Type name or phone..."
|
|
703
|
+
/>
|
|
704
|
+
{comboValue && <p className="text-xs text-muted-foreground mt-2">Selected: {patientOptions.find((o) => o.value === comboValue)?.label}</p>}
|
|
705
|
+
</div>
|
|
706
|
+
</CardContent>
|
|
707
|
+
</Card>
|
|
708
|
+
</Section>
|
|
709
|
+
|
|
710
|
+
{/* ── Calendar ────────────────────────────── */}
|
|
711
|
+
<Section id="calendar" title="Appointment Calendar" description="Week/day/month views with color-coded doctors and drag-and-drop.">
|
|
712
|
+
<Card>
|
|
713
|
+
<CardContent className="pt-6">
|
|
714
|
+
<AppointmentCalendar
|
|
715
|
+
defaultView="week"
|
|
716
|
+
doctors={[
|
|
717
|
+
{ id: "dr-mehmet", name: "Dr. Mehmet", color: "#e77d22" },
|
|
718
|
+
{ id: "dr-elif", name: "Dr. Elif", color: "#3b82f6" },
|
|
719
|
+
{ id: "dr-ayse", name: "Dr. Ayse", color: "#8b5cf6" },
|
|
720
|
+
]}
|
|
721
|
+
events={[
|
|
722
|
+
{ id: "1", title: "Ayse Y. — Root Canal", start: "2026-04-06 09:00", end: "2026-04-06 10:00", calendarId: "dr-mehmet" },
|
|
723
|
+
{ id: "2", title: "Fatma D. — Implant", start: "2026-04-06 10:30", end: "2026-04-06 11:30", calendarId: "dr-elif" },
|
|
724
|
+
{ id: "3", title: "Ahmet K. — Whitening", start: "2026-04-06 14:00", end: "2026-04-06 14:30", calendarId: "dr-mehmet" },
|
|
725
|
+
{ id: "4", title: "Zeynep O. — Botox", start: "2026-04-07 09:00", end: "2026-04-07 09:45", calendarId: "dr-ayse" },
|
|
726
|
+
{ id: "5", title: "Murat C. — Cleaning", start: "2026-04-07 11:00", end: "2026-04-07 11:30", calendarId: "dr-elif" },
|
|
727
|
+
{ id: "6", title: "Selin Y. — Consult", start: "2026-04-08 15:00", end: "2026-04-08 15:30", calendarId: "dr-mehmet" },
|
|
728
|
+
{ id: "7", title: "Can D. — Crown Prep", start: "2026-04-08 10:00", end: "2026-04-08 11:30", calendarId: "dr-ayse" },
|
|
729
|
+
]}
|
|
730
|
+
/>
|
|
731
|
+
</CardContent>
|
|
732
|
+
</Card>
|
|
733
|
+
</Section>
|
|
734
|
+
|
|
735
|
+
{/* ── Confirm Dialog ───────────────────────── */}
|
|
736
|
+
<Section id="confirm" title="Confirm Dialog" description="Confirmation modals for destructive and important actions.">
|
|
737
|
+
<div className="flex gap-3">
|
|
738
|
+
<ConfirmDialog
|
|
739
|
+
trigger={<Button variant="destructive" size="sm"><Trash2 className="w-4 h-4 mr-1.5" />Delete Patient</Button>}
|
|
740
|
+
title="Delete Patient?"
|
|
741
|
+
description="This will permanently deactivate the patient record. This action cannot be undone."
|
|
742
|
+
confirmLabel="Delete"
|
|
743
|
+
variant="destructive"
|
|
744
|
+
onConfirm={() => {}}
|
|
745
|
+
/>
|
|
746
|
+
<ConfirmDialog
|
|
747
|
+
trigger={<Button variant="outline" size="sm">Cancel Appointment</Button>}
|
|
748
|
+
title="Cancel Appointment?"
|
|
749
|
+
description="The patient will be notified about the cancellation."
|
|
750
|
+
confirmLabel="Yes, cancel"
|
|
751
|
+
onConfirm={() => {}}
|
|
752
|
+
/>
|
|
753
|
+
</div>
|
|
754
|
+
</Section>
|
|
755
|
+
|
|
756
|
+
</main>
|
|
757
|
+
</div>
|
|
758
|
+
|
|
759
|
+
{/* ── Footer ─────────────────────────────────── */}
|
|
760
|
+
<footer className="border-t border-border mt-8">
|
|
761
|
+
<div className="max-w-[1440px] mx-auto px-6 py-5 flex justify-between items-center text-xs text-muted-foreground">
|
|
762
|
+
<span>Portal Asistan 7/24 — Clinic Management Platform</span>
|
|
763
|
+
<span>33 shadcn/ui + 14 custom · Tailwind v4 · React 19</span>
|
|
764
|
+
</div>
|
|
765
|
+
</footer>
|
|
766
|
+
</div>
|
|
767
|
+
</TooltipProvider>
|
|
768
|
+
)
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
export default function ComponentsShowcase() {
|
|
772
|
+
return <App />
|
|
773
|
+
}
|