{"id":22330693,"url":"https://github.com/menathndgd/caresync","last_synced_at":"2026-04-08T20:40:42.766Z","repository":{"id":256825697,"uuid":"856514546","full_name":"MenathNDGD/CareSync","owner":"MenathNDGD","description":"CareSync is a modern Patient Management System built with React, Next.js, TailwindCSS, shadcn UI, Appwrite, Sentry, and Twilio. It streamlines patient care by managing appointments, records, and communication, offering real-time notifications and secure data handling.","archived":false,"fork":false,"pushed_at":"2024-10-18T18:48:37.000Z","size":4954,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-24T02:56:26.686Z","etag":null,"topics":["appwrite","full-stack-web-development","nextjs","reactjs","sentry","shadcn-ui","tailwindcss","twilio"],"latest_commit_sha":null,"homepage":"https://care-sync-three.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MenathNDGD.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-12T17:48:30.000Z","updated_at":"2024-10-18T18:57:34.000Z","dependencies_parsed_at":"2024-09-13T08:43:22.028Z","dependency_job_id":"691f79c9-ae00-433b-b580-bbe90d41a245","html_url":"https://github.com/MenathNDGD/CareSync","commit_stats":null,"previous_names":["menathndgd/caresync"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/MenathNDGD/CareSync","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MenathNDGD%2FCareSync","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MenathNDGD%2FCareSync/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MenathNDGD%2FCareSync/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MenathNDGD%2FCareSync/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MenathNDGD","download_url":"https://codeload.github.com/MenathNDGD/CareSync/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MenathNDGD%2FCareSync/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31573788,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["appwrite","full-stack-web-development","nextjs","reactjs","sentry","shadcn-ui","tailwindcss","twilio"],"created_at":"2024-12-04T04:07:33.758Z","updated_at":"2026-04-08T20:40:42.751Z","avatar_url":"https://github.com/MenathNDGD.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cbr /\u003e\n    \u003ca href=\"#\" target=\"_blank\"\u003e\n      \u003cimg src=\"public/assets/icons/logo-full.png\" alt=\"CareSync\"\u003e\n    \u003c/a\u003e\n  \u003cbr /\u003e\n  \u003ch1 align=\"center\"\u003eA HealthCare Management System\u003c/h1\u003e\n  \u003cdiv\u003e\n    \u003cimg src=\"https://img.shields.io/badge/-Next_JS-black?style=for-the-badge\u0026logoColor=white\u0026logo=nextdotjs\u0026color=000000\" alt=\"nextdotjs\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/-TypeScript-black?style=for-the-badge\u0026logoColor=white\u0026logo=typescript\u0026color=3178C6\" alt=\"typescript\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/-Tailwind_CSS-black?style=for-the-badge\u0026logoColor=white\u0026logo=tailwindcss\u0026color=06B6D4\" alt=\"tailwindcss\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/-Appwrite-black?style=for-the-badge\u0026logoColor=white\u0026logo=appwrite\u0026color=FD366E\" alt=\"appwrite\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/shadcn/ui-000000.svg?style=for-the-badge\u0026logo=shadcn/ui\u0026logoColor=white\" alt=\"shadcn/ui\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Twilio-F22F46.svg?style=for-the-badge\u0026logo=Twilio\u0026logoColor=white\" alt=\"twilio\" /\u003e\n  \u003c/div\u003e\n  \u003cbr/\u003e\n   \u003cdiv align=\"center\"\u003e\n     CareSync is a modern Patient Management System built with React, Next.js, TailwindCSS, shadcn UI, Appwrite, Sentry, and Twilio. It streamlines patient care by managing appointments, records, and communication, offering real-time notifications and secure data handling.\n    \u003c/div\u003e\n\u003c/div\u003e\n\n## 📋 \u003ca name=\"table\"\u003eTable of Contents\u003c/a\u003e\n\n1. 🤖 [Introduction](#introduction)\n2. ⚙️ [Tech Stack](#tech-stack)\n3. 🔋 [Features](#features)\n4. 🤸 [Quick Start](#quick-start)\n5. 🕸️ [Snippets (Code to Copy)](#snippets)\n6. 🔗 [Assets](#links)\n7. 📚 [More Features Coming Soon](#more)\n\n## \u003ca name=\"introduction\"\u003e🤖 Introduction\u003c/a\u003e\n\nCareSync is a modern health management platform designed to connect patients and healthcare providers through a seamless, user-friendly interface. The platform enables users to schedule appointments, access medical records, and manage their healthcare needs from one convenient location. With features like real-time notifications, telemedicine, and secure patient data handling, CareSync ensures that managing your healthcare is both efficient and secure.\n\n## \u003ca name=\"tech-stack\"\u003e⚙️ Tech Stack\u003c/a\u003e\n\nOur project leverages a modern and robust tech stack to deliver a seamless experience:\n\n- **Next.js**: A powerful React framework for server-side rendering and static site generation.\n- **Appwrite**: An open-source backend server to manage database, authentication, and more.\n- **TypeScript**: Adds type safety and clarity to our JavaScript code.\n- **TailwindCSS**: A utility-first CSS framework for fast and responsive design.\n- **ShadCN**: A tool for creating accessible and stylish UI components.\n- **Twilio**: A cloud communications platform for SMS, voice, and video integration.\n\nExplore how these technologies come together to power our project!\n\n## \u003ca name=\"features\"\u003e🔋 Features\u003c/a\u003e\n\n- 🎯 **Register as a Patient**: Easy sign-up to create personalized patient profiles.\n\n- 🎯 **Book Appointments**: Effortlessly schedule multiple appointments with doctors.\n\n- 🎯 **Admin Appointment Management**: Admins can view, manage, and handle all appointments.\n\n- 🎯 **Confirm/Schedule Appointments**: Admins ensure smooth scheduling and confirmation.\n\n- 🎯 **Cancel Appointments**: Admins can quickly cancel any appointment.\n\n- 🎯 **Appointment SMS Notifications**: Patients receive instant SMS confirmations upon appointment scheduling.\n\n- 🎯 **Responsive Design**: Seamless experience across all devices and screen sizes.\n\n- 🎯 **Secure File Uploads**: Upload files with confidence using Appwrite Storage.\n\n- 🎯 **Performance Tracking**: Monitor and optimize the app’s performance with Sentry.\n\nand many more, including code architecture and reusability.\n\n## \u003ca name=\"quick-start\"\u003e🤸 Quick Start\u003c/a\u003e\n\nFollow these steps to set up the project locally on your machine.\n\n**Prerequisites**\n\nMake sure you have the following installed on your machine:\n\n- [Git](https://git-scm.com/)\n- [Node.js](https://nodejs.org/en)\n- [NPM](https://www.npmjs.com/) (Node Package Manager)\n\n**Cloning the Repository**\n\n```bash\ngit clone https://github.com/MenathNDGD/CareSync.git\ncd CareSync\n```\n\n**Installation**\n\nInstall the project dependencies using npm:\n\n```bash\nnpm install\n```\n\n**Set Up Environment Variables**\n\nCreate a new file named `.env.local` in the root of your project and add the following content:\n\n```env\n#APPWRITE\nNEXT_PUBLIC_ENDPOINT=https://cloud.appwrite.io/v1\nPROJECT_ID=\nAPI_KEY=\nDATABASE_ID=\nPATIENT_COLLECTION_ID=\nAPPOINTMENT_COLLECTION_ID=\nNEXT_PUBLIC_BUCKET_ID=\n\nNEXT_PUBLIC_ADMIN_PASSKEY=123456\n```\n\nReplace the placeholder values with your actual Appwrite credentials. You can obtain these credentials by signing up on the [Appwrite website](https://appwrite.io/).\n\n**Running the Project**\n\n```bash\nnpm run dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) in your browser to view the project.\n\n## \u003ca name=\"snippets\"\u003e🕸️ Snippets\u003c/a\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003etailwind.config.ts\u003c/code\u003e\u003c/summary\u003e\n\n```typescript\nimport type { Config } from \"tailwindcss\";\n\nconst { fontFamily } = require(\"tailwindcss/defaultTheme\");\n\nconst config = {\n  darkMode: [\"class\"],\n  content: [\n    \"./pages/**/*.{ts,tsx}\",\n    \"./components/**/*.{ts,tsx}\",\n    \"./app/**/*.{ts,tsx}\",\n    \"./src/**/*.{ts,tsx}\",\n  ],\n  prefix: \"\",\n  theme: {\n    container: {\n      center: true,\n      padding: \"2rem\",\n      screens: {\n        \"2xl\": \"1400px\",\n      },\n    },\n    extend: {\n      colors: {\n        green: {\n          500: \"#24AE7C\",\n          600: \"#0D2A1F\",\n        },\n        blue: {\n          500: \"#79B5EC\",\n          600: \"#152432\",\n        },\n        red: {\n          500: \"#F37877\",\n          600: \"#3E1716\",\n          700: \"#F24E43\",\n        },\n        light: {\n          200: \"#E8E9E9\",\n        },\n        dark: {\n          200: \"#0D0F10\",\n          300: \"#131619\",\n          400: \"#1A1D21\",\n          500: \"#363A3D\",\n          600: \"#76828D\",\n          700: \"#ABB8C4\",\n        },\n      },\n      fontFamily: {\n        sans: [\"var(--font-sans)\", ...fontFamily.sans],\n      },\n      backgroundImage: {\n        appointments: \"url('/assets/images/appointments-bg.png')\",\n        pending: \"url('/assets/images/pending-bg.png')\",\n        cancelled: \"url('/assets/images/cancelled-bg.png')\",\n      },\n      keyframes: {\n        \"accordion-down\": {\n          from: { height: \"0\" },\n          to: { height: \"var(--radix-accordion-content-height)\" },\n        },\n        \"accordion-up\": {\n          from: { height: \"var(--radix-accordion-content-height)\" },\n          to: { height: \"0\" },\n        },\n        \"caret-blink\": {\n          \"0%,70%,100%\": { opacity: \"1\" },\n          \"20%,50%\": { opacity: \"0\" },\n        },\n      },\n      animation: {\n        \"accordion-down\": \"accordion-down 0.2s ease-out\",\n        \"accordion-up\": \"accordion-up 0.2s ease-out\",\n        \"caret-blink\": \"caret-blink 1.25s ease-out infinite\",\n      },\n    },\n  },\n  plugins: [require(\"tailwindcss-animate\")],\n} satisfies Config;\n\nexport default config;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eapp/globals.css\u003c/code\u003e\u003c/summary\u003e\n\n```css\n@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n/* ========================================== TAILWIND STYLES */\n@layer base {\n  /* Remove scrollbar */\n  .remove-scrollbar::-webkit-scrollbar {\n    width: 0px;\n    height: 0px;\n    border-radius: 0px;\n  }\n\n  .remove-scrollbar::-webkit-scrollbar-track {\n    background: transparent;\n  }\n\n  .remove-scrollbar::-webkit-scrollbar-thumb {\n    background: transparent;\n    border-radius: 0px;\n  }\n\n  .remove-scrollbar::-webkit-scrollbar-thumb:hover {\n    /* background: #1e2238; */\n    background: transparent;\n  }\n}\n\n@layer utilities {\n  /* ===== UTILITIES */\n  .sidebar {\n    @apply remove-scrollbar w-full max-w-72 flex-col overflow-auto bg-black-800 px-7 py-10;\n  }\n\n  .left-sidebar {\n    @apply hidden lg:flex;\n  }\n\n  .right-sidebar {\n    @apply hidden xl:flex;\n  }\n\n  .clip-text {\n    @apply bg-clip-text text-transparent;\n  }\n\n  .bg-image {\n    @apply bg-black-900 bg-light-rays bg-cover bg-no-repeat;\n  }\n\n  .header {\n    @apply text-32-bold md:text-36-bold;\n  }\n\n  .sub-header {\n    @apply text-18-bold md:text-24-bold;\n  }\n\n  .container {\n    @apply relative flex-1 overflow-y-auto px-[5%];\n  }\n\n  .sub-container {\n    @apply mx-auto flex size-full flex-col py-10;\n  }\n\n  .side-img {\n    @apply hidden h-full object-cover md:block;\n  }\n\n  .copyright {\n    @apply text-14-regular justify-items-end text-center text-dark-600 xl:text-left;\n  }\n\n  /* ==== SUCCESS */\n  .success-img {\n    @apply m-auto flex flex-1 flex-col items-center justify-between gap-10 py-10;\n  }\n\n  .request-details {\n    @apply flex w-full flex-col items-center gap-8 border-y-2 border-dark-400 py-8 md:w-fit md:flex-row;\n  }\n\n  /* ===== ADMIN */\n  .admin-header {\n    @apply sticky top-3 z-20 mx-3 flex items-center justify-between rounded-2xl bg-dark-200 px-[5%] py-5 shadow-lg xl:px-12;\n  }\n\n  .admin-main {\n    @apply flex flex-col items-center space-y-6 px-[5%] pb-12 xl:space-y-12 xl:px-12;\n  }\n\n  .admin-stat {\n    @apply flex w-full flex-col justify-between gap-5 sm:flex-row xl:gap-10;\n  }\n\n  /* ==== FORM */\n  .radio-group {\n    @apply flex h-full flex-1 items-center gap-2 rounded-md border border-dashed border-dark-500 bg-dark-400 p-3;\n  }\n\n  .checkbox-label {\n    @apply cursor-pointer text-sm font-medium text-dark-700 peer-disabled:cursor-not-allowed peer-disabled:opacity-70 md:leading-none;\n  }\n\n  /* ==== File Upload */\n  .file-upload {\n    @apply text-12-regular flex cursor-pointer  flex-col items-center justify-center gap-3 rounded-md border border-dashed border-dark-500 bg-dark-400 p-5;\n  }\n\n  .file-upload_label {\n    @apply flex flex-col justify-center gap-2 text-center text-dark-600;\n  }\n\n  /* ==== Stat Card */\n  .stat-card {\n    @apply flex flex-1 flex-col gap-6 rounded-2xl bg-cover p-6 shadow-lg;\n  }\n\n  /* ==== Status Badge */\n  .status-badge {\n    @apply flex w-fit items-center gap-2 rounded-full px-4 py-2;\n  }\n\n  /* Data Table */\n  .data-table {\n    @apply z-10 w-full overflow-hidden rounded-lg border border-dark-400 shadow-lg;\n  }\n\n  .table-actions {\n    @apply flex w-full items-center justify-between space-x-2 p-4;\n  }\n\n  /* ===== ALIGNMENTS */\n  .flex-center {\n    @apply flex items-center justify-center;\n  }\n\n  .flex-between {\n    @apply flex items-center justify-between;\n  }\n\n  /* ===== TYPOGRAPHY */\n  .text-36-bold {\n    @apply text-[36px] leading-[40px] font-bold;\n  }\n\n  .text-24-bold {\n    @apply text-[24px] leading-[28px] font-bold;\n  }\n\n  .text-32-bold {\n    @apply text-[32px] leading-[36px] font-bold;\n  }\n\n  .text-18-bold {\n    @apply text-[18px] leading-[24px] font-bold;\n  }\n\n  .text-16-semibold {\n    @apply text-[16px] leading-[20px] font-semibold;\n  }\n\n  .text-16-regular {\n    @apply text-[16px] leading-[20px] font-normal;\n  }\n\n  .text-14-medium {\n    @apply text-[14px] leading-[18px] font-medium;\n  }\n\n  .text-14-regular {\n    @apply text-[14px] leading-[18px] font-normal;\n  }\n\n  .text-12-regular {\n    @apply text-[12px] leading-[16px] font-normal;\n  }\n\n  .text-12-semibold {\n    @apply text-[12px] leading-[16px] font-semibold;\n  }\n\n  /* =====  SHADCN OVERRIDES */\n  .shad-primary-btn {\n    @apply bg-green-500 text-white !important;\n  }\n\n  .shad-danger-btn {\n    @apply bg-red-700 text-white !important;\n  }\n\n  .shad-gray-btn {\n    @apply border border-dark-500 cursor-pointer bg-dark-400 text-white !important;\n  }\n\n  .shad-input-label {\n    @apply text-14-medium text-dark-700 !important;\n  }\n\n  .shad-input {\n    @apply bg-dark-400 placeholder:text-dark-600 border-dark-500 h-11 focus-visible:ring-0 focus-visible:ring-offset-0 !important;\n  }\n\n  .shad-input-icon {\n    @apply bg-dark-400 placeholder:text-dark-600 border-dark-500 h-11 focus-visible:ring-0 focus-visible:ring-offset-0 !important;\n  }\n\n  .shad-textArea {\n    @apply bg-dark-400 placeholder:text-dark-600 border-dark-500 focus-visible:ring-0 focus-visible:ring-offset-0 !important;\n  }\n\n  .shad-combobox-item {\n    @apply data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 !important;\n  }\n\n  .shad-combobox-trigger {\n    @apply h-11 !important;\n  }\n\n  .shad-select-trigger {\n    @apply bg-dark-400  placeholder:text-dark-600 border-dark-500 h-11 focus:ring-0 focus:ring-offset-0 !important;\n  }\n\n  .shad-select-content {\n    @apply bg-dark-400 border-dark-500 !important;\n  }\n\n  .shad-dialog {\n    @apply bg-dark-400 border-dark-500 !important;\n  }\n\n  .shad-dialog button {\n    @apply focus:ring-0 focus:ring-offset-0 focus-visible:border-none focus-visible:outline-none focus-visible:ring-transparent focus-visible:ring-offset-0 !important;\n  }\n\n  .shad-error {\n    @apply text-red-400 !important;\n  }\n\n  .shad-table {\n    @apply rounded-lg overflow-hidden !important;\n  }\n\n  .shad-table-row-header {\n    @apply border-b border-dark-400 text-light-200 hover:bg-transparent !important;\n  }\n\n  .shad-table-row {\n    @apply border-b border-dark-400 text-light-200 !important;\n  }\n\n  .shad-otp {\n    @apply w-full flex justify-between !important;\n  }\n\n  .shad-otp-slot {\n    @apply text-36-bold justify-center flex border border-dark-500 rounded-lg size-16 gap-4 !important;\n  }\n\n  .shad-alert-dialog {\n    @apply space-y-5 bg-dark-400 border-dark-500 outline-none !important;\n  }\n\n  .shad-sheet-content button {\n    @apply top-2 focus:ring-0 focus:ring-offset-0 focus-visible:border-none focus-visible:outline-none focus-visible:ring-transparent focus-visible:ring-offset-0 !important;\n  }\n\n  /* =====  REACT PHONE NUMBER INPUT OVERRIDES */\n  .input-phone {\n    @apply mt-2 h-11 rounded-md px-3 text-sm border bg-dark-400 placeholder:text-dark-600 border-dark-500 !important;\n  }\n\n  /* =====  REACT DATE PICKER OVERRIDES */\n  .date-picker {\n    @apply overflow-hidden border-transparent w-full placeholder:text-dark-600  h-11 text-14-medium rounded-md px-3 outline-none !important;\n  }\n}\n\n/* =====  REACT-DATEPICKER OVERRIDES */\n.react-datepicker-wrapper.date-picker {\n  display: flex;\n  align-items: center;\n}\n\n.react-datepicker,\n.react-datepicker__time,\n.react-datepicker__header,\n.react-datepicker__current-month,\n.react-datepicker__day-name,\n.react-datepicker__day,\n.react-datepicker-time__header {\n  background-color: #1a1d21 !important;\n  border-color: #363a3d !important;\n  color: #abb8c4 !important;\n}\n\n.react-datepicker__current-month,\n.react-datepicker__day-name,\n.react-datepicker-time__header {\n  color: #ffffff !important;\n}\n\n.react-datepicker__triangle {\n  fill: #1a1d21 !important;\n  color: #1a1d21 !important;\n  stroke: #1a1d21 !important;\n}\n\n.react-datepicker__time-list-item:hover {\n  background-color: #363a3d !important;\n}\n\n.react-datepicker__input-container input {\n  background-color: #1a1d21 !important;\n  width: 100%;\n  outline: none;\n}\n\n.react-datepicker__day--selected {\n  background-color: #24ae7c !important;\n  color: #ffffff !important;\n  border-radius: 4px;\n}\n\n.react-datepicker__time-list-item--selected {\n  background-color: #24ae7c !important;\n}\n\n.react-datepicker__time-container {\n  border-left: 1px solid #363a3d !important;\n}\n\n.react-datepicker__time-list-item {\n  display: flex !important;\n  align-items: center !important;\n}\n\n/* =====  REACT PHONE NUMBER INPUT OVERRIDES */\n.PhoneInputInput {\n  outline: none;\n  margin-left: 4px;\n  background: #1a1d21;\n  font-size: 14px;\n  font-weight: 500;\n}\n\n.PhoneInputInput::placeholder {\n  color: #1a1d21;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003etypes/index.d.ts\u003c/code\u003e\u003c/summary\u003e\n\n```typescript\n/* eslint-disable no-unused-vars */\n\ndeclare type SearchParamProps = {\n  params: { [key: string]: string };\n  searchParams: { [key: string]: string | string[] | undefined };\n};\n\ndeclare type Gender = \"Male\" | \"Female\" | \"Other\";\ndeclare type Status = \"pending\" | \"scheduled\" | \"cancelled\";\n\ndeclare interface CreateUserParams {\n  name: string;\n  email: string;\n  phone: string;\n}\ndeclare interface User extends CreateUserParams {\n  $id: string;\n}\n\ndeclare interface RegisterUserParams extends CreateUserParams {\n  userId: string;\n  birthDate: Date;\n  gender: Gender;\n  address: string;\n  occupation: string;\n  emergencyContactName: string;\n  emergencyContactNumber: string;\n  primaryPhysician: string;\n  insuranceProvider: string;\n  insurancePolicyNumber: string;\n  allergies: string | undefined;\n  currentMedication: string | undefined;\n  familyMedicalHistory: string | undefined;\n  pastMedicalHistory: string | undefined;\n  identificationType: string | undefined;\n  identificationNumber: string | undefined;\n  identificationDocument: FormData | undefined;\n  privacyConsent: boolean;\n}\n\ndeclare type CreateAppointmentParams = {\n  userId: string;\n  patient: string;\n  primaryPhysician: string;\n  reason: string;\n  schedule: Date;\n  status: Status;\n  note: string | undefined;\n};\n\ndeclare type UpdateAppointmentParams = {\n  appointmentId: string;\n  userId: string;\n  appointment: Appointment;\n  type: string;\n};\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003etypes/appwrite.types.ts\u003c/code\u003e\u003c/summary\u003e\n\n```typescript\nimport { Models } from \"node-appwrite\";\n\nexport interface Patient extends Models.Document {\n  userId: string;\n  name: string;\n  email: string;\n  phone: string;\n  birthDate: Date;\n  gender: Gender;\n  address: string;\n  occupation: string;\n  emergencyContactName: string;\n  emergencyContactNumber: string;\n  primaryPhysician: string;\n  insuranceProvider: string;\n  insurancePolicyNumber: string;\n  allergies: string | undefined;\n  currentMedication: string | undefined;\n  familyMedicalHistory: string | undefined;\n  pastMedicalHistory: string | undefined;\n  identificationType: string | undefined;\n  identificationNumber: string | undefined;\n  identificationDocument: FormData | undefined;\n  privacyConsent: boolean;\n}\n\nexport interface Appointment extends Models.Document {\n  patient: Patient;\n  schedule: Date;\n  status: Status;\n  primaryPhysician: string;\n  reason: string;\n  note: string;\n  userId: string;\n  cancellationReason: string | null;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003elib/utils.ts\u003c/code\u003e\u003c/summary\u003e\n\n```typescript\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport const parseStringify = (value: any) =\u003e JSON.parse(JSON.stringify(value));\n\nexport const convertFileToUrl = (file: File) =\u003e URL.createObjectURL(file);\n\n// FORMAT DATE TIME\nexport const formatDateTime = (dateString: Date | string) =\u003e {\n  const dateTimeOptions: Intl.DateTimeFormatOptions = {\n    // weekday: \"short\", // abbreviated weekday name (e.g., 'Mon')\n    month: \"short\", // abbreviated month name (e.g., 'Oct')\n    day: \"numeric\", // numeric day of the month (e.g., '25')\n    year: \"numeric\", // numeric year (e.g., '2023')\n    hour: \"numeric\", // numeric hour (e.g., '8')\n    minute: \"numeric\", // numeric minute (e.g., '30')\n    hour12: true, // use 12-hour clock (true) or 24-hour clock (false)\n  };\n\n  const dateDayOptions: Intl.DateTimeFormatOptions = {\n    weekday: \"short\", // abbreviated weekday name (e.g., 'Mon')\n    year: \"numeric\", // numeric year (e.g., '2023')\n    month: \"2-digit\", // abbreviated month name (e.g., 'Oct')\n    day: \"2-digit\", // numeric day of the month (e.g., '25')\n  };\n\n  const dateOptions: Intl.DateTimeFormatOptions = {\n    month: \"short\", // abbreviated month name (e.g., 'Oct')\n    year: \"numeric\", // numeric year (e.g., '2023')\n    day: \"numeric\", // numeric day of the month (e.g., '25')\n  };\n\n  const timeOptions: Intl.DateTimeFormatOptions = {\n    hour: \"numeric\", // numeric hour (e.g., '8')\n    minute: \"numeric\", // numeric minute (e.g., '30')\n    hour12: true, // use 12-hour clock (true) or 24-hour clock (false)\n  };\n\n  const formattedDateTime: string = new Date(dateString).toLocaleString(\n    \"en-US\",\n    dateTimeOptions\n  );\n\n  const formattedDateDay: string = new Date(dateString).toLocaleString(\n    \"en-US\",\n    dateDayOptions\n  );\n\n  const formattedDate: string = new Date(dateString).toLocaleString(\n    \"en-US\",\n    dateOptions\n  );\n\n  const formattedTime: string = new Date(dateString).toLocaleString(\n    \"en-US\",\n    timeOptions\n  );\n\n  return {\n    dateTime: formattedDateTime,\n    dateDay: formattedDateDay,\n    dateOnly: formattedDate,\n    timeOnly: formattedTime,\n  };\n};\n\nexport function encryptKey(passkey: string) {\n  return btoa(passkey);\n}\n\nexport function decryptKey(passkey: string) {\n  return atob(passkey);\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003elib/validation.ts\u003c/code\u003e\u003c/summary\u003e\n\n```typescript\nimport { z } from \"zod\";\n\nexport const UserFormValidation = z.object({\n  name: z\n    .string()\n    .min(2, \"Name must be at least 2 characters\")\n    .max(50, \"Name must be at most 50 characters\"),\n  email: z.string().email(\"Invalid email address\"),\n  phone: z\n    .string()\n    .refine((phone) =\u003e /^\\+\\d{10,15}$/.test(phone), \"Invalid phone number\"),\n});\n\nexport const PatientFormValidation = z.object({\n  name: z\n    .string()\n    .min(2, \"Name must be at least 2 characters\")\n    .max(50, \"Name must be at most 50 characters\"),\n  email: z.string().email(\"Invalid email address\"),\n  phone: z\n    .string()\n    .refine((phone) =\u003e /^\\+\\d{10,15}$/.test(phone), \"Invalid phone number\"),\n  birthDate: z.coerce.date(),\n  gender: z.enum([\"Male\", \"Female\", \"Other\"]),\n  address: z\n    .string()\n    .min(5, \"Address must be at least 5 characters\")\n    .max(500, \"Address must be at most 500 characters\"),\n  occupation: z\n    .string()\n    .min(2, \"Occupation must be at least 2 characters\")\n    .max(500, \"Occupation must be at most 500 characters\"),\n  emergencyContactName: z\n    .string()\n    .min(2, \"Contact name must be at least 2 characters\")\n    .max(50, \"Contact name must be at most 50 characters\"),\n  emergencyContactNumber: z\n    .string()\n    .refine(\n      (emergencyContactNumber) =\u003e /^\\+\\d{10,15}$/.test(emergencyContactNumber),\n      \"Invalid phone number\"\n    ),\n  primaryPhysician: z.string().min(2, \"Select at least one doctor\"),\n  insuranceProvider: z\n    .string()\n    .min(2, \"Insurance name must be at least 2 characters\")\n    .max(50, \"Insurance name must be at most 50 characters\"),\n  insurancePolicyNumber: z\n    .string()\n    .min(2, \"Policy number must be at least 2 characters\")\n    .max(50, \"Policy number must be at most 50 characters\"),\n  allergies: z.string().optional(),\n  currentMedication: z.string().optional(),\n  familyMedicalHistory: z.string().optional(),\n  pastMedicalHistory: z.string().optional(),\n  identificationType: z.string().optional(),\n  identificationNumber: z.string().optional(),\n  identificationDocument: z.custom\u003cFile[]\u003e().optional(),\n  treatmentConsent: z\n    .boolean()\n    .default(false)\n    .refine((value) =\u003e value === true, {\n      message: \"You must consent to treatment in order to proceed\",\n    }),\n  disclosureConsent: z\n    .boolean()\n    .default(false)\n    .refine((value) =\u003e value === true, {\n      message: \"You must consent to disclosure in order to proceed\",\n    }),\n  privacyConsent: z\n    .boolean()\n    .default(false)\n    .refine((value) =\u003e value === true, {\n      message: \"You must consent to privacy in order to proceed\",\n    }),\n});\n\nexport const CreateAppointmentSchema = z.object({\n  primaryPhysician: z.string().min(2, \"Select at least one doctor\"),\n  schedule: z.coerce.date(),\n  reason: z\n    .string()\n    .min(2, \"Reason must be at least 2 characters\")\n    .max(500, \"Reason must be at most 500 characters\"),\n  note: z.string().optional(),\n  cancellationReason: z.string().optional(),\n});\n\nexport const ScheduleAppointmentSchema = z.object({\n  primaryPhysician: z.string().min(2, \"Select at least one doctor\"),\n  schedule: z.coerce.date(),\n  reason: z.string().optional(),\n  note: z.string().optional(),\n  cancellationReason: z.string().optional(),\n});\n\nexport const CancelAppointmentSchema = z.object({\n  primaryPhysician: z.string().min(2, \"Select at least one doctor\"),\n  schedule: z.coerce.date(),\n  reason: z.string().optional(),\n  note: z.string().optional(),\n  cancellationReason: z\n    .string()\n    .min(2, \"Reason must be at least 2 characters\")\n    .max(500, \"Reason must be at most 500 characters\"),\n});\n\nexport function getAppointmentSchema(type: string) {\n  switch (type) {\n    case \"create\":\n      return CreateAppointmentSchema;\n    case \"cancel\":\n      return CancelAppointmentSchema;\n    default:\n      return ScheduleAppointmentSchema;\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003econstants/index.ts\u003c/code\u003e\u003c/summary\u003e\n\n```typescript\nexport const GenderOptions = [\"Male\", \"Female\", \"Other\"];\n\nexport const PatientFormDefaultValues = {\n  firstName: \"\",\n  lastName: \"\",\n  email: \"\",\n  phone: \"\",\n  birthDate: new Date(Date.now()),\n  gender: \"Male\" as Gender,\n  address: \"\",\n  occupation: \"\",\n  emergencyContactName: \"\",\n  emergencyContactNumber: \"\",\n  primaryPhysician: \"\",\n  insuranceProvider: \"\",\n  insurancePolicyNumber: \"\",\n  allergies: \"\",\n  currentMedication: \"\",\n  familyMedicalHistory: \"\",\n  pastMedicalHistory: \"\",\n  identificationType: \"Birth Certificate\",\n  identificationNumber: \"\",\n  identificationDocument: [],\n  treatmentConsent: false,\n  disclosureConsent: false,\n  privacyConsent: false,\n};\n\nexport const IdentificationTypes = [\n  \"Birth Certificate\",\n  \"Driver's License\",\n  \"Medical Insurance Card/Policy\",\n  \"Military ID Card\",\n  \"National Identity Card\",\n  \"Passport\",\n  \"Resident Alien Card (Green Card)\",\n  \"Social Security Card\",\n  \"State ID Card\",\n  \"Student ID Card\",\n  \"Voter ID Card\",\n];\n\nexport const Doctors = [\n  {\n    image: \"/assets/images/dr-green.png\",\n    name: \"John Green\",\n  },\n  {\n    image: \"/assets/images/dr-cameron.png\",\n    name: \"Leila Cameron\",\n  },\n  {\n    image: \"/assets/images/dr-livingston.png\",\n    name: \"David Livingston\",\n  },\n  {\n    image: \"/assets/images/dr-peter.png\",\n    name: \"Evan Peter\",\n  },\n  {\n    image: \"/assets/images/dr-powell.png\",\n    name: \"Jane Powell\",\n  },\n  {\n    image: \"/assets/images/dr-remirez.png\",\n    name: \"Alex Ramirez\",\n  },\n  {\n    image: \"/assets/images/dr-lee.png\",\n    name: \"Jasmine Lee\",\n  },\n  {\n    image: \"/assets/images/dr-cruz.png\",\n    name: \"Alyana Cruz\",\n  },\n  {\n    image: \"/assets/images/dr-sharma.png\",\n    name: \"Hardik Sharma\",\n  },\n];\n\nexport const StatusIcon = {\n  scheduled: \"/assets/icons/check.svg\",\n  pending: \"/assets/icons/pending.svg\",\n  cancelled: \"/assets/icons/cancelled.svg\",\n};\n```\n\n\u003c/details\u003e\n\n## \u003ca name=\"links\"\u003e🔗 Assets\u003c/a\u003e\n\nAccess all the public assets used in the project, including images, icons, and other media files, from our shared drive. Feel free to download and explore them:\n\n[Click here to view and download assets](https://drive.google.com/file/d/1yGvWFeSaH1_-aiQ1gejT23lqz5979RKB/view?usp=sharing)\n\nWe've updated our logo for a more modern and refreshing look! The new **CareSync** logo represents our commitment to delivering cutting-edge healthcare management. Here's how to update it in your project:\n\nReplace **logo-full.svg** with **logo-full.png**:\n\n1. Navigate to the `/public/assets/icons/` folder.\n2. Delete `logo-full.svg`.\n3. Add the new **CareSync** logo as `logo-full.png`.\n\nThis new logo aligns perfectly with our mission of simplifying healthcare management. Check it out and let us know what you think!\n\n## \u003ca name=\"more\"\u003e📚 More Features Coming Soon\u003c/a\u003e\n\nWe’re continually enhancing CareSync to provide the best experience possible. Here’s what you can expect in future updates:\n\n- 🌟 **Telemedicine**: Virtual doctor consultations within the app.\n- 🌟 **In-depth Analytics**: Comprehensive reports on patient records and appointment trends.\n- 🌟 **Advanced Security**: Two-factor authentication for enhanced security.\n- 🌟 **Health Reminders**: Personalized notifications for medication, appointments, and more.\n- 🌟 **Integration with Wearables**: Sync health data from smartwatches and fitness trackers.\n\nStay tuned for more exciting features and improvements! 🚀\n\n#\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmenathndgd%2Fcaresync","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmenathndgd%2Fcaresync","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmenathndgd%2Fcaresync/lists"}