├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── add-contributors.yml │ ├── assign.yml │ ├── codeql.yml │ ├── delete-merged-branch.yml │ ├── dependency-review.yml │ ├── label-issues.yml │ ├── pre-commit.yml │ ├── stale.yml │ └── triage.yml ├── .gitignore ├── .husky └── pre-commit ├── .vscode ├── extensions.json └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── biome.json ├── components.json ├── components ├── 2fa │ ├── FirstStep.tsx │ ├── RecoveryCode.tsx │ └── index.ts ├── Protect.tsx ├── about-page │ ├── ContactForm.tsx │ ├── OurAchievements.tsx │ ├── OurPurpose.tsx │ ├── OurTeam.tsx │ └── index.ts ├── campaign-analytics │ ├── Card.tsx │ ├── DonationChart.tsx │ ├── DonationStatsPanel.tsx │ ├── DonationTable.tsx │ ├── MapDisplay.tsx │ ├── SingleCountryDonor.tsx │ ├── SingleTopDonor.tsx │ ├── TopDonators.tsx │ ├── WorldMap.tsx │ └── index.ts ├── campaigns-page │ ├── SuccessStories.tsx │ └── index.ts ├── common │ ├── Avatar.tsx │ ├── CampaignCard.tsx │ ├── CloudflareTurnstile.tsx │ ├── CustomDialog.tsx │ ├── Footer.tsx │ ├── FormErrorMessage.tsx │ ├── Header.tsx │ ├── Heading.tsx │ ├── Loader.tsx │ ├── LogoBanner.tsx │ ├── OtpInputDisplay.tsx │ ├── PageMetaData.tsx │ ├── Pagination.tsx │ ├── SingleCampaignProgress.tsx │ ├── Spinner.tsx │ ├── Success.tsx │ ├── TestimonialCard.tsx │ ├── campaign-icons │ │ ├── ArrowSpinIcon.tsx │ │ ├── ChooseDonation.svg │ │ ├── CrossIcon.tsx │ │ ├── DonorIcon.tsx │ │ ├── DummyAvatar.tsx │ │ ├── MoneyIcon.tsx │ │ ├── SelectFundraiser.svg │ │ ├── ShareIcon.tsx │ │ ├── SubmitDonation.svg │ │ ├── TickIcon.tsx │ │ ├── index.ts │ │ ├── whatsapp.svg │ │ └── x-icon.svg │ ├── dashboardIcons │ │ ├── AnalyticsIcon.tsx │ │ ├── ArrowDown.tsx │ │ ├── BankIcon.tsx │ │ ├── BookmarkIcon.tsx │ │ ├── CampaignIcon.tsx │ │ ├── Chat.tsx │ │ ├── ClockIcon.tsx │ │ ├── DashboardIcon.tsx │ │ ├── EyeIcon.tsx │ │ ├── LocationIcon.tsx │ │ ├── Logo.tsx │ │ ├── MegaphoneIcon.tsx │ │ ├── Menu.tsx │ │ ├── Notification.tsx │ │ ├── PlusIcon.tsx │ │ ├── SettingsIcon.tsx │ │ ├── Star.tsx │ │ ├── UpdatesIcon.tsx │ │ ├── UserIcon.tsx │ │ └── index.ts │ ├── index.ts │ ├── landingPage │ │ ├── CampaignCategories.tsx │ │ ├── FAQ.tsx │ │ ├── Hero.tsx │ │ ├── HowItWorks.tsx │ │ ├── SuccessStories.tsx │ │ ├── UrgentFundraisers.tsx │ │ └── index.ts │ └── svg.tsx ├── create-campaign │ ├── CampaignCarousel.tsx │ ├── CampaignOutlook.tsx │ ├── DonationFlowDialog.tsx │ ├── DonorSection.tsx │ ├── DropZoneInput.tsx │ ├── FormActionButton.tsx │ ├── FormErrorMessage.tsx │ ├── FormSteps │ │ ├── StepOne.tsx │ │ ├── StepThree.tsx │ │ └── StepTwo.tsx │ ├── ImagePreview.tsx │ ├── ShareCampaignDialog.tsx │ ├── StepTracker │ │ ├── StepDetails.tsx │ │ └── StepTracker.tsx │ ├── TipTapEditor │ │ ├── TipTapEditor.tsx │ │ ├── TipTapToolBar.tsx │ │ └── index.ts │ └── index.ts ├── dashboard │ ├── SummaryCard.tsx │ ├── index.ts │ └── settings │ │ ├── Account.tsx │ │ ├── Billing.tsx │ │ ├── Notification.tsx │ │ └── index.ts ├── explore-campaign │ ├── CampaignCategoryCard.tsx │ ├── NoCampaigns.tsx │ └── index.ts └── ui │ ├── accordion.tsx │ ├── button.tsx │ ├── card.tsx │ ├── carousel │ ├── carousel.tsx │ ├── carousel.types.ts │ ├── carouselStoreContext.tsx │ ├── index.ts │ └── useCarouselOptions.ts │ ├── checkbox.tsx │ ├── date-picker │ ├── DateRangePicker.tsx │ ├── calender.tsx │ ├── date-picker.tsx │ ├── index.ts │ └── popover.tsx │ ├── dialog.tsx │ ├── drop-zone.tsx │ ├── dropdown-menu.tsx │ ├── index.ts │ ├── input.tsx │ ├── progressbar.tsx │ ├── select.tsx │ ├── sonner.tsx │ ├── switch.tsx │ ├── table.tsx │ ├── tabs.tsx │ └── toggle.tsx ├── interfaces ├── ApiResponses.ts ├── Campaign.ts ├── Donation.ts ├── FormInputs.ts ├── Layouts.ts ├── SvgProps.ts ├── WithPageLayout.ts └── index.ts ├── layouts ├── AuthPagesLayout.tsx ├── AuthenticatedUserLayout.tsx ├── BaseLayout.tsx └── index.ts ├── lib ├── constants.ts ├── helpers │ ├── callAbegApi.ts │ ├── callApi.ts │ ├── campaign │ │ ├── constants.ts │ │ ├── generateExcerpt.ts │ │ ├── getDateFromString.ts │ │ ├── getEditorExtensions.ts │ │ ├── index.ts │ │ ├── validateFiles.ts │ │ └── validateTagValue.ts │ ├── checkIsDeviceMobileOrTablet.ts │ ├── cn.ts │ ├── create-fetcher │ │ ├── create-fetcher.ts │ │ ├── index.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── getDaysLeft.ts │ ├── getTimeDiff.ts │ ├── omitKeys.ts │ └── parseJSON.ts ├── hooks │ ├── createCustomContext.ts │ ├── index.ts │ ├── useAnimationInterval.ts │ ├── useCallbackRef.ts │ ├── useCloudflareTurnstile.tsx │ ├── useCopyToClipboard.ts │ ├── useDragScroll.ts │ ├── useElementList │ │ ├── For.tsx │ │ └── useElementList.ts │ ├── usePaginate.ts │ ├── usePagination.ts │ ├── useShareCampaign.ts │ ├── useSlot.ts │ ├── useToggle.ts │ └── useWatchInput.ts ├── index.ts ├── type-helpers │ ├── assert.ts │ ├── global.ts │ ├── index.ts │ ├── polymorphism-helper.ts │ └── typeof.ts └── validators │ └── validateWithZod.ts ├── lint-staged.config.js ├── next.config.js ├── package-lock.json ├── package.json ├── pages ├── 2fa │ ├── app.tsx │ ├── authenticate.tsx │ └── index.tsx ├── 404.tsx ├── 500.tsx ├── _app.tsx ├── _document.tsx ├── about │ └── index.tsx ├── api │ └── hello.ts ├── c │ ├── [shortId].tsx │ ├── bookmarks.tsx │ ├── campaigns.tsx │ ├── create.tsx │ ├── index.tsx │ ├── overview.tsx │ ├── preview.tsx │ └── settings.tsx ├── explore │ ├── [categoryId].tsx │ └── index.tsx ├── forgot-password │ └── index.tsx ├── get-started.tsx ├── how-it-works │ └── index.tsx ├── index.tsx ├── reset-password │ ├── index.tsx │ └── success.tsx ├── reveal.tsx ├── signin │ └── index.tsx ├── signup │ ├── index.tsx │ └── verification.tsx └── verify-email │ ├── index.tsx │ └── success.tsx ├── postcss.config.js ├── public ├── assets │ ├── icons │ │ ├── auth │ │ │ ├── arrow-down.svg │ │ │ ├── auth-padlock.svg │ │ │ ├── eye.svg │ │ │ ├── notification-bing.svg │ │ │ └── slashEye.svg │ │ ├── dashboard │ │ │ └── userIcon.svg │ │ └── shared │ │ │ ├── copy.svg │ │ │ ├── google.png │ │ │ └── twitter.png │ ├── images │ │ ├── about-page │ │ │ ├── MagicPattern.png │ │ │ ├── aboutHero.png │ │ │ ├── image-pattern.png │ │ │ ├── index.ts │ │ │ ├── jane.png │ │ │ ├── john-one.png │ │ │ ├── john-two.png │ │ │ ├── our-achievements1.svg │ │ │ ├── our-achievements2.svg │ │ │ ├── our-achievements3.svg │ │ │ ├── our-achievements4.svg │ │ │ └── who-we-are-image.png │ │ ├── auth │ │ │ ├── auth-bg-contourss.png │ │ │ └── auth-bg-jar.svg │ │ ├── campaign-category │ │ │ ├── arrow-down-small.svg │ │ │ ├── arrow-left.svg │ │ │ ├── arrow-right.svg │ │ │ ├── hero-circle.svg │ │ │ ├── hero-half-moon.svg │ │ │ ├── index.ts │ │ │ └── search-icon.svg │ │ ├── dashboard │ │ │ ├── dashboardBg.png │ │ │ ├── dashboardImage.png │ │ │ ├── dummyCardImg.svg │ │ │ └── userIcon.svg │ │ ├── error-pages │ │ │ ├── 404-image.svg │ │ │ ├── 404.svg │ │ │ ├── 500-image.png │ │ │ └── 500.svg │ │ ├── how-it-works │ │ │ ├── how-it-work-hero.png │ │ │ ├── how-it-works-splash.png │ │ │ └── index.ts │ │ ├── landing-page │ │ │ ├── Facebook.svg │ │ │ ├── Instagram.svg │ │ │ ├── LinkedIn.svg │ │ │ ├── MagicPattern.svg │ │ │ ├── Twitter.svg │ │ │ ├── YouTube.svg │ │ │ ├── avatar1.svg │ │ │ ├── avatar2.svg │ │ │ ├── avatar3.svg │ │ │ ├── background.png │ │ │ ├── campaign-hero.svg │ │ │ ├── charity.png │ │ │ ├── close-circle.svg │ │ │ ├── contours.png │ │ │ ├── create-campaign-image1.png │ │ │ ├── create-campaign-image2.png │ │ │ ├── create-campaign-image3.png │ │ │ ├── crowd-fund.svg │ │ │ ├── dropbox.svg │ │ │ ├── envato.svg │ │ │ ├── global-community.svg │ │ │ ├── google.svg │ │ │ ├── happy-people.png │ │ │ ├── hero.svg │ │ │ ├── index.ts │ │ │ ├── join-us.png │ │ │ ├── joinUs.svg │ │ │ ├── menu.svg │ │ │ ├── netflix.svg │ │ │ ├── senville.svg │ │ │ ├── stories-about-us.png │ │ │ ├── support.png │ │ │ ├── testimonial-image1.png │ │ │ ├── testimonial-image2.png │ │ │ ├── testimonial-image3.png │ │ │ └── timecamp.svg │ │ └── shared │ │ │ ├── bg-contours.png │ │ │ ├── contours-old.png │ │ │ ├── hero-background.svg │ │ │ └── logo.svg │ ├── lottie │ │ └── success.json │ └── worldmap.json ├── favicon.ico ├── hero.jpg ├── next.svg └── vercel.svg ├── store ├── index.ts ├── store-types.ts ├── useCampaignStore.ts ├── useFormStore.ts └── useSession.ts ├── styles └── globals.css ├── tailwind.config.ts ├── todo.txt └── tsconfig.json /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## NOTE: 2 | 3 | Type .take as a comment under an issue to automatically assign it to yourself 4 | 5 | ## Issue Type 6 | 7 | - [ ] Bug Report 8 | - [ ] Feature Request 9 | - [ ] Enhancement 10 | - [ ] Other (Please specify) 11 | 12 | ## Description 13 | 14 | [Provide a brief description of the issue or feature request.] 15 | 16 | ## Details 17 | 18 | [Provide more details about the issue or feature request. If it's a bug, include any error messages, unexpected behavior, or other relevant information. If it's a feature request or enhancement, explain why it would be valuable.] 19 | 20 | ## Reproduction Steps (For Bug Reports) 21 | 22 | 1. [Step 1] 23 | 2. [Step 2] 24 | 3. [Step 3] 25 | 26 | ## Expected Behavior (For Bug Reports) 27 | 28 | [Describe what you expected to happen.] 29 | 30 | ## Actual Behavior (For Bug Reports) 31 | 32 | [Describe what actually happened.] 33 | 34 | ## Additional Information 35 | 36 | [Include any additional information that may help in resolving the issue, such as screenshots, logs, or any related links.] 37 | 38 | ## Would you like to contribute to fixing this issue? 39 | 40 | - [ ] Yes 41 | - [ ] No 42 | 43 | ## Related Pull Requests (if any) 44 | 45 | [Link to any related pull requests, if applicable.] 46 | 47 | ## Failure Logs 48 | 49 | Please include any relevant log snippets or files here. 50 | 51 | **Note:** Please make sure to follow the project's code of conduct and contribution guidelines when creating an issue. Thank you for contributing to our open-source project! 52 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Please include a summary of the change and which issue is fixed (if applicable). 4 | 5 | ## Related Issue 6 | 7 | - Fixes # (issue number) 8 | 9 | ## Contribution Guidelines 10 | 11 | Before submitting this pull request, please review our [Contribution Guidelines](https://github.com/abeg-help/frontend/blob/dev/CONTRIBUTING.md) to understand how to contribute to this project. 12 | 13 | ## Checklist 14 | 15 | - [ ] I have reviewed the Contribution Guidelines linked above. 16 | - [ ] I have tested my changes thoroughly and ensured that all existing tests pass. 17 | - [ ] I have provided clear and concise commit messages. 18 | - [ ] I have updated the project's documentation as necessary. 19 | 20 | ## Screenshots (if applicable) 21 | 22 | 23 | 24 | ## Additional context (if needed) 25 | 26 | 27 | -------------------------------------------------------------------------------- /.github/workflows/add-contributors.yml: -------------------------------------------------------------------------------- 1 | name: Add contributors 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - closed 7 | 8 | jobs: 9 | contrib-readme-job: 10 | if: github.event.pull_request.merged == true 11 | runs-on: ubuntu-latest 12 | name: A job to automate contrib in readme 13 | steps: 14 | - name: Contribute List 15 | uses: akhilmhdh/contributors-readme-action@v2.3.6 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} 18 | -------------------------------------------------------------------------------- /.github/workflows/assign.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/take.yml 2 | name: Assign issue to contributor 3 | on: 4 | issue_comment: 5 | 6 | jobs: 7 | assign: 8 | name: Take an issue 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | steps: 13 | - name: take the issue 14 | uses: bdougie/take-action@main 15 | with: 16 | message: Thanks for taking this issue! Let us know if you have any questions! 17 | trigger: .take 18 | token: ${{ secrets.GITHUB_TOKEN }} 19 | -------------------------------------------------------------------------------- /.github/workflows/delete-merged-branch.yml: -------------------------------------------------------------------------------- 1 | name: Delete Merged Branch 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - closed 7 | 8 | jobs: 9 | delete_branch: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Check if pull request was merged 14 | if: github.event.pull_request.merged == true 15 | run: | 16 | source_branch=$(jq --raw-output .pull_request.head.ref "$GITHUB_EVENT_PATH") 17 | base_branch=$(jq --raw-output .pull_request.base.ref "$GITHUB_EVENT_PATH") 18 | 19 | if [[ $source_branch != "main" && $source_branch != "dev" ]]; then 20 | echo "Deleting branch: $source_branch" 21 | git push origin --delete "$source_branch" 22 | else 23 | echo "Branch $source_branch is not deleted since it's 'main' or 'dev'." 24 | fi 25 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. 4 | # 5 | # Source repository: https://github.com/actions/dependency-review-action 6 | # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement 7 | name: "Dependency Review" 8 | on: [pull_request] 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | dependency-review: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: "Checkout Repository" 18 | uses: actions/checkout@v3 19 | - name: "Dependency Review" 20 | uses: actions/dependency-review-action@v3 21 | -------------------------------------------------------------------------------- /.github/workflows/label-issues.yml: -------------------------------------------------------------------------------- 1 | name: Label issues 2 | on: 3 | issues: 4 | types: 5 | - reopened 6 | - opened 7 | jobs: 8 | label_issues: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | steps: 13 | - uses: actions/github-script@v6 14 | with: 15 | script: | 16 | github.rest.issues.addLabels({ 17 | issue_number: context.issue.number, 18 | owner: context.repo.owner, 19 | repo: context.repo.repo, 20 | labels: ["triage"] 21 | }) 22 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - dev 8 | pull_request: 9 | branches: 10 | - main 11 | - dev 12 | 13 | jobs: 14 | ci-checks: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v2 20 | 21 | - name: Setup Node.js 22 | uses: actions/setup-node@v2 23 | with: 24 | node-version: 16 25 | 26 | - name: Install dependencies 27 | run: npm ci 28 | 29 | - name: Run ESLint 30 | run: npm run check-types 31 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | # This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time. 2 | # 3 | # You can adjust the behavior by modifying this file. 4 | # For more information, see: 5 | # https://github.com/actions/stale 6 | name: Mark stale issues and pull requests 7 | 8 | on: 9 | schedule: 10 | - cron: "32 17 * * *" 11 | 12 | jobs: 13 | stale: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | issues: write 17 | pull-requests: write 18 | 19 | steps: 20 | - uses: actions/stale@v5 21 | with: 22 | repo-token: ${{ secrets.GITHUB_TOKEN }} 23 | stale-issue-message: "Stale issue message" 24 | stale-pr-message: "Stale pull request message" 25 | stale-issue-label: "no-issue-activity" 26 | stale-pr-label: "no-pr-activity" 27 | -------------------------------------------------------------------------------- /.github/workflows/triage.yml: -------------------------------------------------------------------------------- 1 | name: "Assign issues with .take" 2 | 3 | on: 4 | issue_comment: 5 | types: 6 | - created 7 | - edited 8 | 9 | jobs: 10 | take-issue: 11 | name: Disable take issue 12 | runs-on: ubuntu-latest 13 | timeout-minutes: 10 14 | steps: 15 | - name: take an issue 16 | uses: bdougie/take-action@main 17 | with: 18 | issueCurrentlyAssignedMessage: Thanks for being interested in this issue. It looks like this ticket is already assigned to someone else. 19 | token: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # env files 4 | .env.local 5 | .env.development.local 6 | .env.test.local 7 | .env.production.local 8 | .env 9 | 10 | # dependencies 11 | /node_modules 12 | /.pnp 13 | .pnp.js 14 | # pnpm lock file 15 | pnpm-lock.yaml 16 | # testing 17 | /coverage 18 | 19 | # next.js 20 | /.next/ 21 | /out/ 22 | 23 | # production 24 | /build 25 | 26 | # misc 27 | .DS_Store 28 | .npmrc 29 | *.pem 30 | 31 | # debug 32 | npm-debug.log* 33 | yarn-debug.log* 34 | yarn-error.log* 35 | 36 | # local env files 37 | .env*.local 38 | .env 39 | 40 | # vercel 41 | .vercel 42 | 43 | # typescript 44 | *.tsbuildinfo 45 | next-env.d.ts 46 | node_modules 47 | .idea 48 | /.idea/ -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "yzhang.markdown-all-in-one", // Markdown All in One 4 | "christian-kohler.path-intellisense", // Path Intellisense, 5 | "eamodio.gitlens", // GitLens — Git supercharged 6 | "wix.vscode-import-cost", // Import Cost, 7 | "formulahendry.auto-rename-tag", // Auto Rename Tag 8 | "streetsidesoftware.code-spell-checker" // Code Spell Checker 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Abeg", 4 | "abeghelpme", 5 | "clsx", 6 | "Didn", 7 | "hookform", 8 | "SEOCONFIG", 9 | "signin", 10 | "signout", 11 | "signup", 12 | "sonner", 13 | "zxcvbn" 14 | ], 15 | 16 | "editor.codeActionsOnSave": { 17 | "source.addMissingImports": "never" 18 | }, 19 | 20 | "tailwindCSS.rootFontSize": 16, 21 | "typescript.tsdk": "node_modules\\typescript\\lib" 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | All Rights Reserved 2 | 3 | Copyright (c) [2023] 4 | 5 | THE CONTENTS OF THIS PROJECT ARE PROPRIETARY AND CONFIDENTIAL. 6 | UNAUTHORIZED COPYING, TRANSFERRING OR REPRODUCTION OF THE CONTENTS OF THIS PROJECT, VIA ANY MEDIUM IS STRICTLY PROHIBITED. 7 | 8 | The receipt or possession of the source code and/or any parts thereof does not convey or imply any right to use them 9 | for any purpose other than the purpose for which they were provided to you. 10 | 11 | The software is provided "AS IS", without warranty of any kind, express or implied, including but not limited to 12 | the warranties of merchantability, fitness for a particular purpose and non infringement. 13 | In no event shall the authors or copyright holders be liable for any claim, damages or other liability, 14 | whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software 15 | or the use or other dealings in the software. 16 | 17 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the software. 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |

🤲 AbegHelp 🤲

4 |

"Abeg, a man of many talents and skills. He is the best in all things."

5 |
6 |
7 |

Find the backend repo here: here

8 |
9 |
10 | 11 | ## Local development 12 | 13 | Install application dependencies 14 | 15 | ```shell 16 | npm install 17 | ``` 18 | 19 | Run Husky 20 | 21 | ```shell 22 | npm run prepare 23 | ``` 24 | 25 | Start a local copy of the app on port `3000` 26 | 27 | ```shell 28 | npm run dev 29 | ``` 30 | 31 | ## Storybook 32 | 33 | The Storybook for this project can be started and viewed locally on port `6006` 34 | 35 | ```shell 36 | npm run storybook 37 | ``` 38 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", 3 | "vcs": { 4 | "enabled": true, 5 | "clientKind": "git", 6 | "useIgnoreFile": true 7 | }, 8 | "organizeImports": { 9 | "enabled": true 10 | }, 11 | "linter": { 12 | "enabled": false 13 | }, 14 | "files": { 15 | "ignoreUnknown": true 16 | }, 17 | "formatter": { 18 | "enabled": true, 19 | "formatWithErrors": true 20 | }, 21 | "javascript": { 22 | "formatter": { 23 | "enabled": true, 24 | "bracketSpacing": true, 25 | "bracketSameLine": false, 26 | "lineWidth": 102, 27 | "semicolons": "always", 28 | "quoteStyle": "double", 29 | "indentWidth": 2, 30 | "trailingComma": "es5", 31 | "arrowParentheses": "always", 32 | "indentStyle": "tab", 33 | "jsxQuoteStyle": "double", 34 | "quoteProperties": "asNeeded" 35 | } 36 | }, 37 | "json": { 38 | "formatter": { 39 | "enabled": true, 40 | "indentStyle": "tab" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "styles/globals.css", 9 | "baseColor": "zinc", 10 | "cssVariables": false 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "utils": "@/lib/utils" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /components/2fa/RecoveryCode.tsx: -------------------------------------------------------------------------------- 1 | import { useCopyToClipboard } from "@/lib/hooks"; 2 | import { ClipboardIcon } from "@radix-ui/react-icons"; 3 | import { toast } from "sonner"; 4 | import { Button } from "../ui"; 5 | 6 | const RecoveryCode = ({ recoveryCode }: { recoveryCode: string | null }) => { 7 | const { copyToClipboard } = useCopyToClipboard(); 8 | 9 | const handleCopy = () => { 10 | copyToClipboard(recoveryCode as string); 11 | 12 | toast.success("Success", { 13 | description: "Key copied to clipboard", 14 | }); 15 | }; 16 | 17 | return ( 18 |
19 |

20 | Two-factor authentication is enabled 21 |

22 |

23 | We’ll now ask for a login code whenever you want to log in so that 24 | we're sure it's you 25 |

26 |

27 | Make sure to secure your recovery key in safe place . Without these, you 28 | may not be able to disable 2FA your account if you lose access to your 29 | phone or can’t log in using your security method. 30 |

31 |
32 |
33 |

Recovery Key

34 |
35 | {recoveryCode} 36 | 43 |
44 |
45 |

46 | Keep your recovery key in a secure place as it is the only code that 47 | can be used to disable your 2FA 48 |

49 |
50 |
51 | ); 52 | }; 53 | 54 | export default RecoveryCode; 55 | -------------------------------------------------------------------------------- /components/2fa/index.ts: -------------------------------------------------------------------------------- 1 | //2FA 2 | export { default as FirstStep } from "./FirstStep"; 3 | export { default as RecoveryCode } from "./RecoveryCode"; 4 | -------------------------------------------------------------------------------- /components/about-page/OurAchievements.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ourAchievements1, 3 | ourAchievements2, 4 | ourAchievements3, 5 | ourAchievements4, 6 | } from "@/public/assets/images/about-page"; 7 | import Image from "next/image"; 8 | 9 | const ourAchievements = [ 10 | { 11 | figure: "1,500", 12 | title: "Campaigns Completed", 13 | image: ourAchievements1, 14 | }, 15 | { 16 | figure: "20 Million", 17 | title: "Raised to Date", 18 | image: ourAchievements2, 19 | }, 20 | { 21 | figure: "950", 22 | title: "Partner Fundinds", 23 | image: ourAchievements3, 24 | }, 25 | { 26 | figure: "7,000", 27 | title: "Happy Repeat Customers", 28 | image: ourAchievements4, 29 | }, 30 | ]; 31 | const OurAchievements = () => { 32 | return ( 33 |
34 | {ourAchievements.map((achievement, index) => ( 35 |
39 | hero image 45 |
46 |

47 | {achievement.figure} 48 |

49 |

50 | {achievement.title} 51 |

52 |
53 |
54 | ))} 55 |
56 | ); 57 | }; 58 | export default OurAchievements; 59 | -------------------------------------------------------------------------------- /components/about-page/OurTeam.tsx: -------------------------------------------------------------------------------- 1 | import { JaneDoe, JohnDoe1, JohnDoe2 } from "@/public/assets/images/about-page"; 2 | import Image from "next/image"; 3 | 4 | const ourTeam = [ 5 | { 6 | name: "John Doe", 7 | position: "UI UX Designer", 8 | image: JohnDoe1, 9 | }, 10 | { 11 | name: "John Doe", 12 | position: "Frontend Engineer", 13 | image: JohnDoe2, 14 | }, 15 | { 16 | name: "Jane Doe", 17 | position: "Frontend Engineer", 18 | image: JaneDoe, 19 | }, 20 | { 21 | name: "John Doe", 22 | position: "Frontend Engineer", 23 | image: JohnDoe1, 24 | }, 25 | { 26 | name: "John Doe", 27 | position: "Frontend Engineer", 28 | image: JohnDoe2, 29 | }, 30 | { 31 | name: "John Doe", 32 | position: "Support Engineer", 33 | image: JohnDoe1, 34 | }, 35 | { 36 | name: "John Doe", 37 | position: "Team Lead", 38 | image: JohnDoe2, 39 | }, 40 | ]; 41 | const OurTeam = () => { 42 | return ( 43 |
44 |
45 |

Meet the team

46 |

47 | A pack of achievers with a dream 48 |

49 |
50 |
51 | {ourTeam.map((dev, index) => ( 52 |
53 | {dev.name} 60 | 61 |

{dev.name}

62 |

{dev.position}

63 |
64 |
65 | ))} 66 |
67 |
68 | ); 69 | }; 70 | export default OurTeam; 71 | -------------------------------------------------------------------------------- /components/about-page/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ContactForm } from "./ContactForm"; 2 | export { default as OurAchievements } from "./OurAchievements"; 3 | export { default as OurTeam } from "./OurTeam"; 4 | export { default as OurPurpose } from "./OurPurpose"; 5 | -------------------------------------------------------------------------------- /components/campaign-analytics/Card.tsx: -------------------------------------------------------------------------------- 1 | import { ReceiveIcon } from "@/components/common"; 2 | // import { Button } from "@/components/ui"; 3 | import { useState } from "react"; 4 | 5 | type CardProps = { title: string; amount?: string; analytics?: string }; 6 | const Card = ({ title, amount = "0", analytics = "+ 0%" }: CardProps) => { 7 | const [item, setItem] = useState("All item"); 8 | 9 | return ( 10 |
11 |
12 | 13 |

Total {title}

14 |
15 |
16 |

{amount}

17 |

{analytics}

18 |
19 |
20 | ); 21 | }; 22 | 23 | export default Card; 24 | -------------------------------------------------------------------------------- /components/campaign-analytics/DonationStatsPanel.tsx: -------------------------------------------------------------------------------- 1 | import { DonationChart } from "@/components/campaign-analytics"; 2 | 3 | const DonationStatsPanel = () => ( 4 |
5 | 6 |
7 | ); 8 | 9 | export default DonationStatsPanel; 10 | -------------------------------------------------------------------------------- /components/campaign-analytics/MapDisplay.tsx: -------------------------------------------------------------------------------- 1 | import SingleCountryDonor from "./SingleCountryDonor"; 2 | import WorldMap from "./WorldMap"; 3 | 4 | const MapDisplay = () => { 5 | return ( 6 |
7 |
8 |

Total donors so far

9 |

10 | Real time report 11 |

12 |
13 |
14 | 15 |
16 |

10.8K

17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 |
27 |
28 | ); 29 | }; 30 | 31 | export default MapDisplay; 32 | -------------------------------------------------------------------------------- /components/campaign-analytics/SingleCountryDonor.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | CameroonFlag, 3 | GambiaFlag, 4 | GhanaFlag, 5 | LiberiaFlag, 6 | MaliFlag, 7 | NigeriaFlag, 8 | } from "@/components/common"; 9 | import { ProgressBar } from "@/components/ui"; 10 | 11 | type CountryData = { 12 | country: "Nigeria" | "Ghana" | "Mali" | "Liberia" | "Cameroon" | "Gambia"; 13 | flag: JSX.Element; 14 | }; 15 | 16 | type CountryMap = { 17 | [key: string]: CountryData; 18 | }; 19 | 20 | type Country = { 21 | countryName: string; 22 | progress: number; 23 | }; 24 | 25 | const Countries: CountryMap = { 26 | Nigeria: { 27 | country: "Nigeria", 28 | flag: , 29 | }, 30 | Ghana: { 31 | country: "Ghana", 32 | flag: , 33 | }, 34 | Mali: { 35 | country: "Mali", 36 | flag: , 37 | }, 38 | Liberia: { 39 | country: "Liberia", 40 | flag: , 41 | }, 42 | Cameroon: { 43 | country: "Cameroon", 44 | flag: , 45 | }, 46 | Gambia: { 47 | country: "Gambia", 48 | flag: , 49 | }, 50 | }; 51 | 52 | const SingleCountryDonor = ({ countryName, progress }: Country) => { 53 | const { country, flag } = Countries[countryName]; 54 | return ( 55 |
56 |
57 | {flag} 58 |
59 |
60 |

{country}

61 |
62 | 66 |

{progress}%

67 |
68 |
69 |
70 | ); 71 | }; 72 | 73 | export default SingleCountryDonor; 74 | -------------------------------------------------------------------------------- /components/campaign-analytics/SingleTopDonor.tsx: -------------------------------------------------------------------------------- 1 | import { AbegHelpLogoWhite } from "@/components/common"; 2 | import { ProgressBar } from "@/components/ui"; 3 | 4 | type Props = { 5 | name: string; 6 | type: string; 7 | donated: number; 8 | target: number; 9 | }; 10 | const SingleTopDonor = ({ name, type, donated, target }: Props) => { 11 | return ( 12 |
13 |
14 | 15 |
16 |

{name}

17 |

{type}

18 |
19 |
20 |
21 |
22 |

${donated}

23 |

Target: ${target}

24 |
25 | 29 |
30 |
31 | ); 32 | }; 33 | export default SingleTopDonor; 34 | -------------------------------------------------------------------------------- /components/campaign-analytics/TopDonators.tsx: -------------------------------------------------------------------------------- 1 | import { SingleTopDonor } from "@/components/campaign-analytics"; 2 | 3 | const dummyData = [ 4 | { 5 | name: "Example Charity Org.", 6 | type: "Corporate Donor", 7 | donated: 30, 8 | }, 9 | { 10 | name: "Example Charity Org.", 11 | type: "Corporate Donor", 12 | donated: 378, 13 | }, 14 | { 15 | name: "Example Charity Org.", 16 | type: "Corporate Donor", 17 | donated: 307, 18 | target: 1000, 19 | }, 20 | { 21 | name: "Example Charity Org.", 22 | type: "Corporate Donor", 23 | donated: 450, 24 | }, 25 | { 26 | name: "Example Charity Org.", 27 | type: "Corporate Donor", 28 | donated: 30, 29 | }, 30 | { 31 | name: "Example Charity Org.", 32 | type: "Corporate Donor", 33 | donated: 700, 34 | }, 35 | ]; 36 | const TopDonators = () => { 37 | return ( 38 |
39 |

40 | Top Donors 41 |

42 |
43 | {dummyData.map((data, id) => { 44 | return ( 45 | 52 | ); 53 | })} 54 |
55 |
56 | ); 57 | }; 58 | export default TopDonators; 59 | -------------------------------------------------------------------------------- /components/campaign-analytics/WorldMap.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ComposableMap, 3 | Geographies, 4 | Geography, 5 | Marker, 6 | } from "react-simple-maps"; 7 | 8 | type CountriesMap = { 9 | [key: string]: { coordinates: [number, number] }; 10 | }; 11 | 12 | const Countries: CountriesMap = { 13 | Nigeria: { 14 | coordinates: [9.0563, 7.4985], 15 | }, 16 | Ghana: { 17 | coordinates: [7.9465, 1.0232], 18 | }, 19 | Mali: { 20 | coordinates: [17.5707, 3.9962], 21 | }, 22 | Liberia: { 23 | coordinates: [6.4281, 9.4295], 24 | }, 25 | Cameroon: { 26 | coordinates: [7.3697, 12.3547], 27 | }, 28 | Gambia: { 29 | coordinates: [13.4432, 15.3101], 30 | }, 31 | }; 32 | 33 | const WorldMap = ({ countries }: { countries?: string[] }) => { 34 | return ( 35 | <> 36 | 40 | 41 | {({ geographies }) => 42 | geographies.map((geo) => ( 43 | 51 | )) 52 | } 53 | 54 | {countries?.map((name) => ( 55 | 56 | 63 | 64 | ))} 65 | 66 | 67 | ); 68 | }; 69 | 70 | export default WorldMap; 71 | -------------------------------------------------------------------------------- /components/campaign-analytics/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Card } from "./Card"; 2 | export { default as WorldMap } from "./WorldMap"; 3 | export { default as SingleCountryDonor } from "./SingleCountryDonor"; 4 | export { default as DonationChart } from "./DonationChart"; 5 | export { default as DonationTable } from "./DonationTable"; 6 | export { default as TopDonators } from "./TopDonators"; 7 | export { default as DonationStatsPanel } from "./DonationStatsPanel"; 8 | export { default as SingleTopDonor } from "./SingleTopDonor"; 9 | -------------------------------------------------------------------------------- /components/campaigns-page/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SuccessStories } from "./SuccessStories"; 2 | -------------------------------------------------------------------------------- /components/common/Avatar.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | type AvatarProps = { 4 | initials: string; 5 | src?: string; 6 | alt?: string; 7 | }; 8 | const Avatar = ({ src, alt, initials }: AvatarProps) => { 9 | return ( 10 |
11 | {src && {alt} 12 | {initials || "AH"} 13 |
14 | ); 15 | }; 16 | 17 | export default Avatar; 18 | -------------------------------------------------------------------------------- /components/common/CloudflareTurnstile.tsx: -------------------------------------------------------------------------------- 1 | import type { ForwardedRefType } from "@/lib/type-helpers"; 2 | import { assertENV } from "@/lib/type-helpers/assert"; 3 | import { Turnstile, type TurnstileInstance } from "@marsidev/react-turnstile"; 4 | import { type MutableRefObject, forwardRef, useEffect, useState } from "react"; 5 | 6 | type ValidRefType = Extract< 7 | TRef, 8 | MutableRefObject 9 | >; 10 | 11 | type TurnstileProps = { 12 | onStatusChange: (status: "success" | "idle" | "error") => void; 13 | }; 14 | 15 | function CloudFlareTurnStileComp( 16 | props: TurnstileProps, 17 | ref: ForwardedRefType 18 | ) { 19 | const { onStatusChange } = props; 20 | const [status, setStatus] = useState<"success" | "idle" | "error">("idle"); 21 | 22 | const SITEKEY = assertENV(process.env.NEXT_PUBLIC_CF_TURNSTILE_SITEKEY, { 23 | message: 24 | "Please add the NEXT_PUBLIC_CF_TURNSTILE_SITEKEY variable to your .env file", 25 | }); 26 | 27 | useEffect(() => { 28 | onStatusChange(status); 29 | }, [status]); 30 | 31 | return ( 32 | setStatus("error")} 40 | onSuccess={() => setStatus("success")} 41 | onExpire={() => ref && (ref as ValidRefType).current?.reset()} 42 | /> 43 | ); 44 | } 45 | 46 | export default forwardRef(CloudFlareTurnStileComp); 47 | -------------------------------------------------------------------------------- /components/common/CustomDialog.tsx: -------------------------------------------------------------------------------- 1 | import { Dialog } from "@/components/ui"; 2 | import { cn } from "@/lib"; 3 | import type { DialogProps } from "@radix-ui/react-dialog"; 4 | import { CrossCircledIcon } from "@radix-ui/react-icons"; 5 | import type { ReactNode } from "react"; 6 | 7 | type CustomDialogProps = { 8 | children: ReactNode; 9 | trigger?: ReactNode; 10 | isOpen?: boolean; 11 | hasCloseButton?: boolean; 12 | classNames?: { 13 | content?: string; 14 | }; 15 | setIsOpen?: DialogProps["onOpenChange"]; 16 | }; 17 | 18 | function CustomDialog(props: CustomDialogProps) { 19 | const { 20 | children, 21 | classNames, 22 | trigger, 23 | isOpen, 24 | setIsOpen, 25 | hasCloseButton = true, 26 | } = props; 27 | 28 | return ( 29 | 30 | {trigger} 31 | 32 | 35 | {children} 36 | 37 | {hasCloseButton && ( 38 | 39 | 40 | 41 | Close 42 | 43 | )} 44 | 45 | 46 | ); 47 | } 48 | 49 | export default CustomDialog; 50 | -------------------------------------------------------------------------------- /components/common/FormErrorMessage.tsx: -------------------------------------------------------------------------------- 1 | import type { SignUpProps } from "@/interfaces"; 2 | import { memo } from "react"; 3 | import type { FieldErrors } from "react-hook-form"; 4 | import { ProgressBar } from "../ui"; 5 | 6 | type FormErrorMessageProps = { 7 | error?: FieldErrors; 8 | errorMsg?: string; 9 | isForPasswordStrength?: boolean; 10 | result?: number; 11 | }; 12 | const FormErrorMessage = memo( 13 | ({ 14 | error, 15 | errorMsg, 16 | isForPasswordStrength, 17 | result, 18 | }: FormErrorMessageProps) => { 19 | if (isForPasswordStrength && result) { 20 | return ( 21 |
22 | = 2 && result <= 3 28 | ? "progress-filled:bg-yellow-500" 29 | : "progress-filled:bg-green-500" 30 | }`} 31 | /> 32 |

= 2 && result <= 3 37 | ? "text-yellow-500" 38 | : "text-green-500" 39 | } text-sm`} 40 | > 41 | Password strength: 42 |   43 | {result < 2 44 | ? "Weak" 45 | : result >= 2 && result <= 3 46 | ? "Medium" 47 | : "Strong"} 48 |

49 |
50 | ); 51 | } else 52 | return error &&

{errorMsg}

; 53 | } 54 | ); 55 | 56 | export default FormErrorMessage; 57 | -------------------------------------------------------------------------------- /components/common/Heading.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib"; 2 | import type { PolymorphicProps } from "@/lib/type-helpers/polymorphism-helper"; 3 | 4 | type HeadingElements = keyof typeof semanticHeadings; 5 | 6 | type HeadingProps = { 7 | as: TElement; 8 | children: React.ReactNode; 9 | className?: string; 10 | }; 11 | 12 | const semanticHeadings = { 13 | h1: "font-bold text-base lg:text-2xl", 14 | h2: "font-bold text-base lg:text-2xl", 15 | h3: "font-bold text-base lg:text-xl", 16 | h4: "font-medium text-xs lg:text-xl", 17 | }; 18 | 19 | function Heading( 20 | props: PolymorphicProps> 21 | ) { 22 | const { 23 | as: HeadingElement = "h1", 24 | children, 25 | className, 26 | ...restOfProps 27 | } = props; 28 | 29 | const HEADING_CLASSES = cn(semanticHeadings[HeadingElement], className); 30 | 31 | return ( 32 | 33 | {children} 34 | 35 | ); 36 | } 37 | 38 | export default Heading; 39 | -------------------------------------------------------------------------------- /components/common/Loader.tsx: -------------------------------------------------------------------------------- 1 | import LogoBanner from "./LogoBanner"; 2 | 3 | type CompProp = { 4 | message?: string | JSX.Element; 5 | }; 6 | 7 | const Loader = ({ message }: CompProp) => { 8 | return ( 9 |
10 | 11 |

{message}

12 |
13 | ); 14 | }; 15 | 16 | export default Loader; 17 | -------------------------------------------------------------------------------- /components/common/LogoBanner.tsx: -------------------------------------------------------------------------------- 1 | import logo from "@/public/assets/images/shared/logo.svg"; 2 | import Image from "next/image"; 3 | import Link from "next/link"; 4 | 5 | const LogoBanner = ({ className }: { className?: string }) => { 6 | return ( 7 | 8 | logo 14 | 18 | AbegHelp.me 19 | 20 | 21 | ); 22 | }; 23 | 24 | export default LogoBanner; 25 | -------------------------------------------------------------------------------- /components/common/OtpInputDisplay.tsx: -------------------------------------------------------------------------------- 1 | // import Button from '../primitives/Button/button'; 2 | import React from "react"; 3 | import OTPInput from "react-otp-input"; 4 | 5 | type OtpProps = { 6 | otp: string; 7 | setOtp: React.Dispatch>; 8 | topSection?: React.ReactNode; 9 | bottomSection?: React.ReactNode; 10 | }; 11 | 12 | const OtpInputDisplay = ({ 13 | otp, 14 | setOtp, 15 | topSection, 16 | bottomSection, 17 | }: OtpProps) => { 18 | return ( 19 |
20 |
21 |

22 | Enter your verification code 23 |

24 | {topSection} 25 | } 33 | /> 34 |
35 | {bottomSection} 36 |
37 | ); 38 | }; 39 | 40 | export default OtpInputDisplay; 41 | -------------------------------------------------------------------------------- /components/common/PageMetaData.tsx: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | // import type { ReactNode } from "react"; 3 | interface MetaDataProps { 4 | // children: ReactNode, 5 | title: string; 6 | content: string; 7 | image?: string; 8 | url?: string; 9 | } 10 | 11 | const PageMetaData = ({ title, content, image, url }: MetaDataProps) => { 12 | return ( 13 | 14 | // Primary Meta Tags 15 | {`Abeg Help | ${title}`} 16 | 17 | 18 | 19 | 20 | 21 | // Open Graph / Facebook 22 | 23 | {url && } 24 | 25 | 26 | {image && } 27 | // Twitter 28 | {image && } 29 | {image && } 30 | {url && } 31 | {image && } 32 | {image && } 33 | {image && } 34 | 35 | 36 | {image && } 37 | 38 | ); 39 | }; 40 | 41 | export default PageMetaData; 42 | -------------------------------------------------------------------------------- /components/common/Pagination.tsx: -------------------------------------------------------------------------------- 1 | import { Pagination as PaginationPrimitive } from "@nextui-org/pagination"; 2 | import { ArrowLeft } from "./svg"; 3 | 4 | type PaginationProps = { 5 | startPage?: number; 6 | currentPage: number; 7 | totalPageCount: number; 8 | onPageChange: (value: number | "prev" | "next") => void; 9 | }; 10 | 11 | function Pagination(props: PaginationProps) { 12 | const { currentPage, totalPageCount, startPage = 1, onPageChange } = props; 13 | 14 | return ( 15 |
16 | 23 | 24 | 35 | 36 | 43 |
44 | ); 45 | } 46 | export default Pagination; 47 | -------------------------------------------------------------------------------- /components/common/Spinner.tsx: -------------------------------------------------------------------------------- 1 | const Spinner = () => { 2 | return ( 3 |
7 | 23 | Loading... 24 | Loading... 25 |
26 | ); 27 | }; 28 | 29 | export default Spinner; 30 | -------------------------------------------------------------------------------- /components/common/Success.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib"; 2 | import dynamic from "next/dynamic"; 3 | import type { ReactNode } from "react"; 4 | import SuccessLottie from "../../public/assets/lottie/success.json"; 5 | 6 | const Lottie = dynamic(async () => import("lottie-react"), { ssr: false }); 7 | 8 | type SuccessProps = { 9 | children?: ReactNode; 10 | description: string; 11 | classNames?: { 12 | lottiePlayer?: string; 13 | wrapper?: string; 14 | heading?: string; 15 | description?: string; 16 | }; 17 | }; 18 | 19 | const Success = ({ children, description, classNames }: SuccessProps) => { 20 | return ( 21 |
27 | 33 |
34 |

35 | Success! 36 |

37 |

{description}

38 |
39 | {children} 40 |
41 | ); 42 | }; 43 | 44 | export default Success; 45 | -------------------------------------------------------------------------------- /components/common/campaign-icons/ArrowSpinIcon.tsx: -------------------------------------------------------------------------------- 1 | const ArrowSpinIcon = (props: React.SVGProps) => ( 2 | 9 | 15 | 16 | ); 17 | 18 | export default ArrowSpinIcon; 19 | -------------------------------------------------------------------------------- /components/common/campaign-icons/CrossIcon.tsx: -------------------------------------------------------------------------------- 1 | const CrossIcon = (props: React.SVGProps) => ( 2 | 10 | 17 | 24 | 25 | ); 26 | export default CrossIcon; 27 | -------------------------------------------------------------------------------- /components/common/campaign-icons/DonorIcon.tsx: -------------------------------------------------------------------------------- 1 | const semanticStrokes = { 2 | light: "stroke-white", 3 | green: "stroke-abeg-primary", 4 | dark: "stroke-abeg-text", 5 | }; 6 | 7 | const DonorIcon = ( 8 | props: React.SVGProps & { stroke?: "light" | "green" | "dark" } 9 | ) => { 10 | const { stroke = "green", ...restOfProps } = props; 11 | 12 | return ( 13 | 21 | 28 | 35 | 42 | 49 | 50 | ); 51 | }; 52 | 53 | export default DonorIcon; 54 | -------------------------------------------------------------------------------- /components/common/campaign-icons/MoneyIcon.tsx: -------------------------------------------------------------------------------- 1 | const MoneyIcon = (props: React.SVGProps) => ( 2 | 10 | 11 | 20 | 29 | 38 | 47 | 48 | 49 | ); 50 | 51 | export default MoneyIcon; 52 | -------------------------------------------------------------------------------- /components/common/campaign-icons/SelectFundraiser.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /components/common/campaign-icons/ShareIcon.tsx: -------------------------------------------------------------------------------- 1 | const shareIcon = (props: React.SVGProps) => ( 2 | 10 | 17 | 24 | 31 | 38 | 45 | 52 | 53 | ); 54 | 55 | export default shareIcon; 56 | -------------------------------------------------------------------------------- /components/common/campaign-icons/SubmitDonation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /components/common/campaign-icons/TickIcon.tsx: -------------------------------------------------------------------------------- 1 | const TickIcon = (props: React.SVGProps) => ( 2 | 10 | 11 | 12 | 20 | 28 | 29 | 30 | 31 | ); 32 | 33 | export default TickIcon; 34 | -------------------------------------------------------------------------------- /components/common/campaign-icons/index.ts: -------------------------------------------------------------------------------- 1 | export { default as CrossIcon } from "./CrossIcon"; 2 | export { default as MoneyIcon } from "./MoneyIcon"; 3 | export { default as TickIcon } from "./TickIcon"; 4 | export { default as ArrowSpinIcon } from "./ArrowSpinIcon"; 5 | export { default as DummyAvatar } from "./DummyAvatar"; 6 | export { default as DonorIcon } from "./DonorIcon"; 7 | export { default as ShareIcon } from "./ShareIcon"; 8 | export { default as xIcon } from "./x-icon.svg"; 9 | export { default as whatsappIcon } from "./whatsapp.svg"; 10 | -------------------------------------------------------------------------------- /components/common/campaign-icons/whatsapp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/AnalyticsIcon.tsx: -------------------------------------------------------------------------------- 1 | import type { FillSvgProps } from "@/interfaces"; 2 | 3 | const AnalyticsIcon = ({ fill, stroke }: FillSvgProps) => ( 4 | 11 | 19 | 27 | 35 | 43 | 51 | 52 | ); 53 | export default AnalyticsIcon; 54 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/ArrowDown.tsx: -------------------------------------------------------------------------------- 1 | export const ArrowDown = () => ( 2 | 9 | 17 | 18 | ); 19 | export default ArrowDown; 20 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/BookmarkIcon.tsx: -------------------------------------------------------------------------------- 1 | import type { FillSvgProps } from "@/interfaces"; 2 | 3 | function BookmarkIcon({ fill, stroke }: FillSvgProps) { 4 | return ( 5 | 12 | 19 | 26 | 33 | 34 | ); 35 | } 36 | export default BookmarkIcon; 37 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/CampaignIcon.tsx: -------------------------------------------------------------------------------- 1 | import type { FillSvgProps } from "@/interfaces"; 2 | 3 | function CampaignIcon({ 4 | fill, 5 | stroke, 6 | ...props 7 | }: Omit, "fill" | "stroke"> & FillSvgProps) { 8 | return ( 9 | 17 | 24 | 31 | 32 | ); 33 | } 34 | 35 | export default CampaignIcon; 36 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/Chat.tsx: -------------------------------------------------------------------------------- 1 | const Chat = () => ( 2 | 9 | 10 | 17 | 24 | 25 | ); 26 | export default Chat; 27 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/ClockIcon.tsx: -------------------------------------------------------------------------------- 1 | const ClockIcon = (props: React.SVGProps) => { 2 | return ( 3 | 11 | 18 | 25 | 26 | ); 27 | }; 28 | 29 | export default ClockIcon; 30 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/DashboardIcon.tsx: -------------------------------------------------------------------------------- 1 | import type { FillSvgProps } from "@/interfaces"; 2 | 3 | const DashboardIcon = ({ fill, stroke }: FillSvgProps) => ( 4 | 11 | 18 | 25 | 26 | ); 27 | export default DashboardIcon; 28 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/EyeIcon.tsx: -------------------------------------------------------------------------------- 1 | const EyeIcon = () => { 2 | return ( 3 | 10 | 17 | 24 | 25 | ); 26 | }; 27 | 28 | export default EyeIcon; 29 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/LocationIcon.tsx: -------------------------------------------------------------------------------- 1 | const LocationIcon = (props: React.SVGProps) => { 2 | return ( 3 | 11 | 16 | 21 | 22 | ); 23 | }; 24 | 25 | export default LocationIcon; 26 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/Logo.tsx: -------------------------------------------------------------------------------- 1 | const Logo = () => ( 2 | 9 | 15 | 21 | 27 | 28 | ); 29 | export default Logo; 30 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/MegaphoneIcon.tsx: -------------------------------------------------------------------------------- 1 | import type { FillSvgProps } from "@/interfaces"; 2 | 3 | const MegaphoneIcon = ({ fill, stroke }: FillSvgProps) => { 4 | return ( 5 | 18 | 25 | 32 | 33 | ); 34 | }; 35 | 36 | export default MegaphoneIcon; 37 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/Menu.tsx: -------------------------------------------------------------------------------- 1 | const Menu = () => ( 2 | 9 | 16 | 17 | ); 18 | export default Menu; 19 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/Notification.tsx: -------------------------------------------------------------------------------- 1 | const Notification = () => ( 2 | 9 | 16 | 24 | 30 | 31 | ); 32 | export default Notification; 33 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/PlusIcon.tsx: -------------------------------------------------------------------------------- 1 | import type { FillSvgProps } from "@/interfaces"; 2 | 3 | const PlusIcon = ({ fill }: FillSvgProps) => ( 4 | 11 | 15 | 16 | ); 17 | export default PlusIcon; 18 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/SettingsIcon.tsx: -------------------------------------------------------------------------------- 1 | import type { FillSvgProps } from "@/interfaces"; 2 | 3 | const SettingsIcon = ({ fill, stroke }: FillSvgProps) => ( 4 | 11 | 20 | 28 | 29 | ); 30 | export default SettingsIcon; 31 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/UpdatesIcon.tsx: -------------------------------------------------------------------------------- 1 | import type { FillSvgProps } from "@/interfaces"; 2 | 3 | const UpdatesIcon = ({ fill, stroke }: FillSvgProps) => ( 4 | 11 | 18 | 26 | 27 | ); 28 | export default UpdatesIcon; 29 | -------------------------------------------------------------------------------- /components/common/dashboardIcons/index.ts: -------------------------------------------------------------------------------- 1 | //dashboard icons 2 | export { default as AnalyticsIcon } from "./AnalyticsIcon"; 3 | export { default as ArrowDown } from "./ArrowDown"; 4 | export { default as BankIcon } from "./BankIcon"; 5 | export { default as Chat } from "./Chat"; 6 | export { default as ClockIcon } from "./ClockIcon"; 7 | export { default as DashboardIcon } from "./DashboardIcon"; 8 | export { default as EyeIcon } from "./EyeIcon"; 9 | export { default as LocationIcon } from "./LocationIcon"; 10 | export { default as Logo } from "./Logo"; 11 | export { default as MegaphoneIcon } from "./MegaphoneIcon"; 12 | export { default as Menu } from "./Menu"; 13 | export { default as Notification } from "./Notification"; 14 | export { default as PlusIcon } from "./PlusIcon"; 15 | export { default as SettingsIcon } from "./SettingsIcon"; 16 | export { default as UpdatesIcon } from "./UpdatesIcon"; 17 | export { default as CampaignIcon } from "./CampaignIcon"; 18 | export { default as BookmarkIcon } from "./BookmarkIcon"; 19 | export { default as UserIcon } from "./UserIcon"; 20 | -------------------------------------------------------------------------------- /components/common/index.ts: -------------------------------------------------------------------------------- 1 | //SHARED 2 | export { default as Avatar } from "./Avatar"; 3 | export { default as CloudFlareTurnStile } from "./CloudflareTurnstile"; 4 | export { default as CustomDialog } from "./CustomDialog"; 5 | export { default as Footer } from "./Footer"; 6 | export { default as Heading } from "./Heading"; 7 | export { default as FormErrorMessage } from "./FormErrorMessage"; 8 | export { default as Header } from "./Header"; 9 | export { default as Loader } from "./Loader"; 10 | export { default as LogoBanner } from "./LogoBanner"; 11 | export { default as OtpInputDisplay } from "./OtpInputDisplay"; 12 | export { default as PageMetaData } from "./PageMetaData"; 13 | export { default as Spinner } from "./Spinner"; 14 | export { default as Success } from "./Success"; 15 | export * from "./dashboardIcons"; 16 | export { 17 | AbegHelpLogo, 18 | AbegHelpLogoWhite, 19 | CameroonFlag, 20 | CloseIcon, 21 | ClosedIcon, 22 | DraftsIcon, 23 | FilterIcon, 24 | GambiaFlag, 25 | GhanaFlag, 26 | Hamburger, 27 | LiberiaFlag, 28 | MaliFlag, 29 | NigeriaFlag, 30 | ReceiveIcon, 31 | SlashedStarIcon, 32 | StarIcon, 33 | Moneys, 34 | VerifiedIcon, 35 | WalletAdd, 36 | TotalDonors, 37 | BringPositiveChangeStar, 38 | Spark, 39 | Smiley, 40 | Sun, 41 | Cup, 42 | Heart, 43 | ArrowUpRight, 44 | Settings, 45 | AccountIcon, 46 | BillingIcon, 47 | NotificationIcon, 48 | EditIcon, 49 | UploadIcon, 50 | } from "./svg"; 51 | export { default as SingleCampaignProgress } from "./SingleCampaignProgress"; 52 | export { default as Pagination } from "./Pagination"; 53 | -------------------------------------------------------------------------------- /components/common/landingPage/CampaignCategories.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "@/components/ui"; 2 | import type { AllCampaignCategories } from "@/interfaces"; 3 | import { cn } from "@/lib"; 4 | import Link from "next/link"; 5 | 6 | const CampaignCategories = ({ 7 | className, 8 | allCampaignCategories, 9 | }: { 10 | className?: string; 11 | allCampaignCategories?: AllCampaignCategories[]; 12 | }) => { 13 | return ( 14 |
15 |
16 |

Campaign Categories

17 |

18 | See the list of campaign categories in Abeghelp.me and get started to 19 | empower your cause and that of others 20 |

21 |
22 |
23 | {allCampaignCategories && 24 | allCampaignCategories.map((category, id) => { 25 | return ( 26 | 44 | ); 45 | })} 46 |
47 |
48 | ); 49 | }; 50 | export default CampaignCategories; 51 | -------------------------------------------------------------------------------- /components/common/landingPage/SuccessStories.tsx: -------------------------------------------------------------------------------- 1 | const SuccessStories = () => { 2 | return ( 3 |
4 |

5 | The Success stories of the
6 | benefactors speak for themselves 7 |

8 |
9 |
10 |
11 |
12 | ); 13 | }; 14 | export default SuccessStories; 15 | -------------------------------------------------------------------------------- /components/common/landingPage/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Hero } from "./Hero"; 2 | export { default as CampaignCategories } from "./CampaignCategories"; 3 | export { default as FAQ } from "./FAQ"; 4 | export { default as UrgentFundraisers } from "./UrgentFundraisers"; 5 | export { default as HowItWorks } from "./HowItWorks"; 6 | -------------------------------------------------------------------------------- /components/create-campaign/DonorSection.tsx: -------------------------------------------------------------------------------- 1 | import { DummyAvatar } from "@/components/common/campaign-icons"; 2 | import type { Donation } from "@/interfaces/Donation"; 3 | import { cn } from "@/lib"; 4 | import { getTimeDifference } from "@/lib/helpers/getTimeDiff"; 5 | import { useElementList } from "@/lib/hooks"; 6 | import { Button } from "../ui"; 7 | 8 | function DonorSection({ 9 | className, 10 | donations, 11 | }: { 12 | className?: string; 13 | donations?: Donation[]; 14 | }) { 15 | const [DonorList] = useElementList(); 16 | 17 | return ( 18 |
19 | {donations && donations?.length > 0 ? ( 20 | ( 24 |
  • 25 |
    26 | 27 | 28 |
    29 | {donation?.donorName} 30 |
    31 |
    32 | 33 |

    34 | sent 35 | 36 | 37 | +{donation?.amount?.toLocaleString("US")} 38 | 39 | 40 | {getTimeDifference(String(donation?.createdAt ?? "")) ?? "few mins ago"} 41 |

    42 |
  • 43 | )} 44 | /> 45 | ) : ( 46 |

    No donations yet.

    47 | )} 48 | 49 | {donations?.length! > 0 && ( 50 | 56 | )} 57 |
    58 | ); 59 | } 60 | 61 | export default DonorSection; 62 | -------------------------------------------------------------------------------- /components/create-campaign/DropZoneInput.tsx: -------------------------------------------------------------------------------- 1 | import { Button, DropZone, type DropZoneProps } from "@/components/ui"; 2 | import { validateFiles } from "@/lib/helpers/campaign"; 3 | import { allowedFileTypes } from "@/lib/helpers/campaign/validateFiles"; 4 | import { type StepThreeData, useFormStore } from "@/store"; 5 | import { toast } from "sonner"; 6 | 7 | type DropZoneInputProps = { 8 | value: StepThreeData["photos"]; 9 | onChange: (files: StepThreeData["photos"]) => void; 10 | }; 11 | 12 | function DropZoneInput(props: DropZoneInputProps) { 13 | const { value: imageFilesOrString, onChange } = props; 14 | 15 | const { updateFormData } = useFormStore((state) => state.actions); 16 | 17 | const handleImageUpload: DropZoneProps["onDrop"] = ({ acceptedFiles }) => { 18 | const newFileState = [...imageFilesOrString, ...acceptedFiles]; 19 | 20 | updateFormData({ photos: newFileState }); 21 | 22 | onChange(newFileState); 23 | 24 | toast.success("Success", { 25 | description: `Uploaded ${acceptedFiles.length} file${acceptedFiles.length > 1 ? "s" : ""}!`, 26 | }); 27 | }; 28 | 29 | const realImageFiles = imageFilesOrString.filter((file): file is File => file instanceof File); 30 | 31 | return ( 32 | 42 | 49 | 50 |
    51 |

    Click to select files, or Drag {`'n'`} Drop

    52 | 53 |

    Support files; PDF, JPG, CSV

    54 | 55 |

    Not more than 5mb

    56 |
    57 |
    58 | ); 59 | } 60 | 61 | export default DropZoneInput; 62 | -------------------------------------------------------------------------------- /components/create-campaign/FormActionButton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib"; 2 | import type { Control } from "react-hook-form"; 3 | import { useFormState } from "react-hook-form"; 4 | import { Button } from "../ui"; 5 | 6 | type BaseProps = { 7 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 8 | isSubmitting?: boolean; 9 | disabled?: boolean; 10 | targetForm?: string; 11 | asChild?: boolean; 12 | type: "button" | "submit"; 13 | variant?: "primary" | "secondary" | "danger"; 14 | className?: string; 15 | onClick?: () => void; 16 | }; 17 | 18 | type FormActionButtonProps = BaseProps & ({ text: string } | { children: React.ReactNode }); 19 | 20 | function FormActionButton(props: FormActionButtonProps) { 21 | const { 22 | targetForm, 23 | isSubmitting, 24 | disabled, 25 | asChild, 26 | variant = "primary", 27 | className, 28 | type, 29 | onClick, 30 | ...restOfProps 31 | } = props; 32 | 33 | return ( 34 | 50 | ); 51 | } 52 | 53 | export default FormActionButton; 54 | -------------------------------------------------------------------------------- /components/create-campaign/FormErrorMessage.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib"; 2 | import { useEffect, useRef } from "react"; 3 | import { type Control, type FieldValues, useFormState } from "react-hook-form"; 4 | 5 | type ErrorParagraphProps = { 6 | className?: string; 7 | control: Control; 8 | errorField: keyof TStepData; 9 | }; 10 | 11 | function FormErrorMessage(props: ErrorParagraphProps) { 12 | const { className, control, errorField } = props; 13 | 14 | const formState = useFormState({ control }); 15 | 16 | const errorParagraphRef = useRef(null); 17 | const message = formState.errors[errorField]?.message as string | undefined; 18 | 19 | const animationClass = "animate-shake"; 20 | 21 | console.log(formState.errors); 22 | console.dir(errorParagraphRef.current); 23 | 24 | useEffect(() => { 25 | if (!errorParagraphRef.current) return; 26 | 27 | if (errorParagraphRef.current.classList.contains(animationClass)) return; 28 | 29 | errorParagraphRef.current.classList.add(animationClass); 30 | 31 | // Scroll to first error message 32 | if (Object.keys(formState.errors).indexOf(errorField as string) === 0) { 33 | errorParagraphRef.current.scrollIntoView({ 34 | behavior: "smooth", 35 | block: "center", 36 | }); 37 | } 38 | }, [formState.submitCount]); 39 | 40 | if (!message) { 41 | return null; 42 | } 43 | 44 | return ( 45 |

    errorParagraphRef.current?.classList.remove(animationClass)} 49 | > 50 | *{message} 51 |

    52 | ); 53 | } 54 | 55 | export default FormErrorMessage; 56 | -------------------------------------------------------------------------------- /components/create-campaign/StepTracker/StepDetails.tsx: -------------------------------------------------------------------------------- 1 | import { TickIcon } from "@/components/common/campaign-icons"; 2 | import { cn } from "@/lib"; 3 | import type { FormStore } from "@/store"; 4 | import Heading from "../../common/Heading"; 5 | 6 | type StepIndicatorProps = { 7 | step: FormStore["currentStep"]; 8 | disabled?: boolean; 9 | isCompleted?: boolean; 10 | }; 11 | 12 | type StepInfoProps = Pick & { 13 | title: string; 14 | description: string; 15 | }; 16 | 17 | function StepIndicator(props: StepIndicatorProps) { 18 | const { step, isCompleted = false, disabled = false } = props; 19 | 20 | const Separator = ( 21 |
    27 | ); 28 | 29 | return ( 30 |
    1 && "flex basis-full flex-col items-center")}> 31 | {step > 1 && Separator} 32 | 33 | 39 | {isCompleted ? : step} 40 | 41 |
    42 | ); 43 | } 44 | 45 | function StepInformation({ 46 | title, 47 | description, 48 | disabled = false, 49 | }: StepInfoProps) { 50 | return ( 51 |
    52 | {title} 53 | 54 |

    {description}

    55 |
    56 | ); 57 | } 58 | 59 | export { StepIndicator, StepInformation }; 60 | -------------------------------------------------------------------------------- /components/create-campaign/StepTracker/StepTracker.tsx: -------------------------------------------------------------------------------- 1 | import { useFormStore } from "@/store"; 2 | import { StepIndicator, StepInformation } from "./StepDetails"; 3 | 4 | function StepTracker() { 5 | const currentStep = useFormStore((state) => state.currentStep); 6 | 7 | return ( 8 | <> 9 |
    10 | 1} /> 11 | 12 | 2} 16 | /> 17 | 18 | 19 |
    20 | 21 |
    22 | 26 | 27 | 32 | 33 | 38 |
    39 | 40 | ); 41 | } 42 | 43 | export default StepTracker; 44 | -------------------------------------------------------------------------------- /components/create-campaign/TipTapEditor/TipTapToolBar.tsx: -------------------------------------------------------------------------------- 1 | import { Toggle } from "@/components/ui"; 2 | import type { Editor } from "@tiptap/react"; 3 | import { 4 | BoldIcon, 5 | ItalicIcon, 6 | ListIcon, 7 | ListOrderedIcon, 8 | Trash2Icon, 9 | } from "lucide-react"; 10 | 11 | type ToolBarProps = { editor: Editor }; 12 | 13 | function TipTapToolBar({ editor }: ToolBarProps) { 14 | return ( 15 |
    16 | editor.chain().focus().toggleBold().run()} 19 | > 20 | 21 | 22 | 23 | editor.chain().focus().toggleItalic().run()} 26 | > 27 | 28 | 29 | 30 | editor.chain().focus().toggleBulletList().run()} 33 | > 34 | 35 | 36 | 37 | editor.chain().focus().toggleOrderedList().run()} 40 | > 41 | 42 | 43 | 44 | 51 |
    52 | ); 53 | } 54 | 55 | export default TipTapToolBar; 56 | -------------------------------------------------------------------------------- /components/create-campaign/TipTapEditor/index.ts: -------------------------------------------------------------------------------- 1 | export { default as TipTapEditor } from "./TipTapEditor"; 2 | -------------------------------------------------------------------------------- /components/create-campaign/index.ts: -------------------------------------------------------------------------------- 1 | export { default as FormErrorMessage } from "./FormErrorMessage"; 2 | export { default as FormActionButton } from "./FormActionButton"; 3 | export { default as StepOne } from "./FormSteps/StepOne"; 4 | export { default as StepThree } from "./FormSteps/StepThree"; 5 | export { default as StepTwo } from "./FormSteps/StepTwo"; 6 | export { default as DonorSection } from "./DonorSection"; 7 | export { default as StepTracker } from "./StepTracker/StepTracker"; 8 | export { default as CampaignOutlook } from "./CampaignOutlook"; 9 | export { default as CampaignCarousel } from "./CampaignCarousel"; 10 | -------------------------------------------------------------------------------- /components/dashboard/SummaryCard.tsx: -------------------------------------------------------------------------------- 1 | type SummaryCardProps = { 2 | title: string; 3 | figure: string | number; 4 | result: string; 5 | }; 6 | const SummaryCard = ({ title, figure, result }: SummaryCardProps) => { 7 | return ( 8 |
    9 |

    10 | 18 | 25 | 32 | 39 | 45 | 51 | 57 | 58 | 59 | total {title} 60 | 61 |

    62 |
    63 |

    {figure}

    64 | {result} 65 |
    66 |
    67 | ); 68 | }; 69 | 70 | export default SummaryCard; 71 | -------------------------------------------------------------------------------- /components/dashboard/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SummaryCard } from "./SummaryCard"; 2 | -------------------------------------------------------------------------------- /components/dashboard/settings/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Account } from "./Account"; 2 | export { default as Notification } from "./Notification"; 3 | export { default as Billing } from "./Billing"; 4 | -------------------------------------------------------------------------------- /components/explore-campaign/NoCampaigns.tsx: -------------------------------------------------------------------------------- 1 | type NoCampaignProps = { 2 | categoryName: string | null; 3 | }; 4 | const NoCampaign = ({ categoryName }: NoCampaignProps) => { 5 | return ( 6 |
    7 |

    8 | There are currently no campaign in 9 | {` ${categoryName?.toLowerCase()} campaign`} 10 |

    11 |

    12 | Try other campaign categories above 13 |

    14 |
    15 | ); 16 | }; 17 | export default NoCampaign; 18 | -------------------------------------------------------------------------------- /components/explore-campaign/index.ts: -------------------------------------------------------------------------------- 1 | export { default as CampaignCategoryCard } from "./CampaignCategoryCard"; 2 | -------------------------------------------------------------------------------- /components/ui/accordion.tsx: -------------------------------------------------------------------------------- 1 | import * as AccordionPrimitive from "@radix-ui/react-accordion"; 2 | import { ChevronDownIcon } from "@radix-ui/react-icons"; 3 | import * as React from "react"; 4 | 5 | import { cn } from "@/lib"; 6 | 7 | const Accordion = AccordionPrimitive.Root; 8 | 9 | const AccordionItem = React.forwardRef< 10 | React.ElementRef, 11 | React.ComponentPropsWithoutRef 12 | >(({ className, ...props }, ref) => ( 13 | 18 | )); 19 | AccordionItem.displayName = "AccordionItem"; 20 | 21 | const AccordionTrigger = React.forwardRef< 22 | React.ElementRef, 23 | React.ComponentPropsWithoutRef 24 | >(({ className, children, ...props }, ref) => ( 25 | 26 | svg]:rotate-180", 30 | className 31 | )} 32 | {...props} 33 | > 34 | {children} 35 | 36 | 37 | 38 | )); 39 | AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName; 40 | 41 | const AccordionContent = React.forwardRef< 42 | React.ElementRef, 43 | React.ComponentPropsWithoutRef 44 | >(({ className, children, ...props }, ref) => ( 45 | 50 |
    {children}
    51 |
    52 | )); 53 | AccordionContent.displayName = AccordionPrimitive.Content.displayName; 54 | 55 | export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; 56 | -------------------------------------------------------------------------------- /components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import type { PolymorphicProps } from "@/lib/type-helpers"; 2 | import { Slot } from "@radix-ui/react-slot"; 3 | 4 | type CardProps = { 5 | className?: string; 6 | children?: React.ReactNode; 7 | }; 8 | 9 | function Card( 10 | props: PolymorphicProps 11 | ) { 12 | const { as: Element = "article", children, asChild, ...restOfProps } = props; 13 | 14 | const Component = asChild ? Slot : Element; 15 | 16 | return {children}; 17 | } 18 | 19 | function CardHeader( 20 | props: PolymorphicProps 21 | ) { 22 | const { as: Element = "header", asChild, children, ...restOfProps } = props; 23 | 24 | const Component = asChild ? Slot : Element; 25 | 26 | return {children}; 27 | } 28 | 29 | function CardContent( 30 | props: PolymorphicProps 31 | ) { 32 | const { as: Element = "div", children, ...restOfProps } = props; 33 | 34 | return {children}; 35 | } 36 | 37 | function CardFooter( 38 | props: PolymorphicProps 39 | ) { 40 | const { as: Element = "footer", children, ...restOfProps } = props; 41 | 42 | return {children}; 43 | } 44 | 45 | Card.Header = CardHeader; 46 | Card.Content = CardContent; 47 | Card.Footer = CardFooter; 48 | 49 | export default Card; 50 | -------------------------------------------------------------------------------- /components/ui/carousel/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Carousel } from "./carousel"; 2 | export type * from "./carousel.types"; 3 | -------------------------------------------------------------------------------- /components/ui/carousel/useCarouselOptions.ts: -------------------------------------------------------------------------------- 1 | import { useAnimationInterval } from "@/lib/hooks/useAnimationInterval"; 2 | import { useCallbackRef } from "@/lib/hooks/useCallbackRef"; 3 | import { useState } from "react"; 4 | import { useCarouselStore } from "./carouselStoreContext"; 5 | 6 | type CarouselOptions = { 7 | hasAutoSlide?: boolean; 8 | autoSlideInterval?: number; 9 | shouldPauseOnHover?: boolean; 10 | }; 11 | 12 | const useCarouselOptions = (options: CarouselOptions = {}) => { 13 | const { 14 | hasAutoSlide = false, 15 | autoSlideInterval = 5000, 16 | shouldPauseOnHover = false, 17 | } = options; 18 | 19 | const { nextSlide } = useCarouselStore((state) => state.actions); 20 | 21 | const [isPaused, setIsPaused] = useState(false); 22 | 23 | const shouldAutoSlide = hasAutoSlide && !isPaused; 24 | 25 | useAnimationInterval({ 26 | callbackFn: nextSlide, 27 | intervalDuration: shouldAutoSlide ? autoSlideInterval : null, 28 | }); 29 | 30 | const pauseAutoSlide = useCallbackRef( 31 | () => shouldPauseOnHover && setIsPaused(true) 32 | ); 33 | 34 | const resumeAutoSlide = useCallbackRef( 35 | () => shouldPauseOnHover && setIsPaused(false) 36 | ); 37 | 38 | return { pauseAutoSlide, resumeAutoSlide }; 39 | }; 40 | 41 | export { useCarouselOptions }; 42 | -------------------------------------------------------------------------------- /components/ui/checkbox.tsx: -------------------------------------------------------------------------------- 1 | import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; 2 | import { CheckIcon } from "@radix-ui/react-icons"; 3 | import * as React from "react"; 4 | 5 | import { cn } from "@/lib"; 6 | 7 | const Checkbox = React.forwardRef< 8 | React.ElementRef, 9 | React.ComponentPropsWithoutRef 10 | >(({ className, ...props }, ref) => ( 11 | 19 | 22 | 23 | 24 | 25 | )); 26 | Checkbox.displayName = CheckboxPrimitive.Root.displayName; 27 | 28 | export { Checkbox }; 29 | -------------------------------------------------------------------------------- /components/ui/date-picker/DateRangePicker.tsx: -------------------------------------------------------------------------------- 1 | import { CalendarIcon } from "@radix-ui/react-icons"; 2 | import { addDays, format } from "date-fns"; 3 | import * as React from "react"; 4 | 5 | import { cn } from "@/lib"; 6 | import { 7 | Popover, 8 | PopoverContent, 9 | PopoverTrigger, 10 | } from "@radix-ui/react-popover"; 11 | import type { DateRange } from "react-day-picker"; 12 | import Button from "../button"; 13 | import Calendar from "./calender"; 14 | 15 | export function DateRangePicker({ 16 | className, 17 | }: React.HTMLAttributes) { 18 | const [date, setDate] = React.useState({ 19 | from: new Date(2024, 0, 1), 20 | to: addDays(new Date(2024, 0, 20), 20), 21 | }); 22 | 23 | return ( 24 |
    25 | 26 | 27 | 49 | 50 | 54 | 62 | 63 | 64 |
    65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /components/ui/date-picker/date-picker.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib"; 2 | import { DATE_NEXT_TOMORROW } from "@/lib/helpers/campaign/constants"; 3 | import { getDateFromString } from "@/lib/helpers/campaign/getDateFromString"; 4 | import { format } from "date-fns"; 5 | import { CalendarIcon } from "lucide-react"; 6 | import { buttonVariants } from "../button"; 7 | import Calendar from "./calender"; 8 | import { Popover } from "./popover"; 9 | 10 | type DatePickerProps = { 11 | className?: string; 12 | placeholder?: string; 13 | dateValueString: string; 14 | onChange: (dateValueString?: string) => void; 15 | }; 16 | 17 | function DatePicker(props: DatePickerProps) { 18 | const { placeholder, dateValueString = "", className, onChange } = props; 19 | 20 | const dateValue = getDateFromString(dateValueString, DATE_NEXT_TOMORROW); 21 | 22 | const isDateSelected = dateValueString !== ""; 23 | 24 | return ( 25 | 26 | 27 | 38 | 39 | 40 | { 49 | if (!date) return; 50 | 51 | onChange(format(date, "MM-dd-yyyy")); 52 | }} 53 | initialFocus={true} 54 | disabled={{ before: DATE_NEXT_TOMORROW }} 55 | /> 56 | 57 | 58 | ); 59 | } 60 | 61 | export default DatePicker; 62 | -------------------------------------------------------------------------------- /components/ui/date-picker/index.ts: -------------------------------------------------------------------------------- 1 | export { DateRangePicker } from "./DateRangePicker"; 2 | export { default as DatePicker } from "./date-picker"; 3 | -------------------------------------------------------------------------------- /components/ui/date-picker/popover.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib"; 2 | import type { ForwardedRefType, InferProps } from "@/lib/type-helpers"; 3 | import * as PopoverPrimitive from "@radix-ui/react-popover"; 4 | import { forwardRef } from "react"; 5 | 6 | function PopoverContent( 7 | props: InferProps, 8 | ref: ForwardedRefType 9 | ) { 10 | const { className, align = "center", sideOffset = 4, ...restOfProps } = props; 11 | 12 | return ( 13 | 14 | 24 | 25 | ); 26 | } 27 | 28 | const Popover = { 29 | Root: PopoverPrimitive.Root, 30 | Content: forwardRef(PopoverContent), 31 | Trigger: PopoverPrimitive.Trigger, 32 | }; 33 | 34 | export { Popover }; 35 | -------------------------------------------------------------------------------- /components/ui/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Button } from "./button"; 2 | 3 | export { default as Dialog } from "./dialog"; 4 | 5 | export { 6 | default as Dropdown, 7 | DropdownMenu, 8 | DropdownMenuTrigger, 9 | DropdownMenuContent, 10 | DropdownMenuItem, 11 | DropdownMenuCheckboxItem, 12 | DropdownMenuRadioItem, 13 | DropdownMenuLabel, 14 | DropdownMenuSeparator, 15 | DropdownMenuShortcut, 16 | DropdownMenuGroup, 17 | DropdownMenuPortal, 18 | DropdownMenuSub, 19 | DropdownMenuSubContent, 20 | DropdownMenuSubTrigger, 21 | DropdownMenuRadioGroup, 22 | } from "./dropdown-menu"; 23 | 24 | export { 25 | Table, 26 | TableHeader, 27 | TableBody, 28 | TableFooter, 29 | TableHead, 30 | TableRow, 31 | TableCell, 32 | TableCaption, 33 | } from "./table"; 34 | 35 | export { default as Input } from "./input"; 36 | export { default as ProgressBar } from "./progressbar"; 37 | export { Toaster } from "./sonner"; 38 | 39 | export { Select, SelectPrimitive } from "./select"; 40 | export { DatePicker } from "./date-picker"; 41 | export { default as Toggle } from "./toggle"; 42 | export { default as Card } from "./card"; 43 | export { default as Tabs } from "./tabs"; 44 | export { Switch } from "./switch"; 45 | export { Checkbox } from "./checkbox"; 46 | export { default as DropZone, type DropZoneProps } from "./drop-zone"; 47 | -------------------------------------------------------------------------------- /components/ui/progressbar.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib"; 2 | 3 | interface ProgressBarProps { 4 | value: number; 5 | className?: string; 6 | } 7 | 8 | const ProgressBar = ({ value, className, ...props }: ProgressBarProps) => { 9 | return ( 10 | 20 | {`${value}%`} 21 | 22 | ); 23 | }; 24 | 25 | export default ProgressBar; 26 | -------------------------------------------------------------------------------- /components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | import { useTheme } from "next-themes"; 2 | import { Toaster as Sonner } from "sonner"; 3 | 4 | type ToasterProps = React.ComponentProps; 5 | 6 | const Toaster = (props: ToasterProps) => { 7 | const { theme = "system" } = useTheme(); 8 | 9 | return ( 10 | 37 | ); 38 | }; 39 | 40 | export { Toaster }; 41 | -------------------------------------------------------------------------------- /components/ui/switch.tsx: -------------------------------------------------------------------------------- 1 | import * as SwitchPrimitives from "@radix-ui/react-switch"; 2 | import * as React from "react"; 3 | 4 | import { cn } from "@/lib"; 5 | 6 | const Switch = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >(({ className, ...props }, ref) => ( 10 | 18 | 23 | 24 | )); 25 | Switch.displayName = SwitchPrimitives.Root.displayName; 26 | 27 | export { Switch }; 28 | -------------------------------------------------------------------------------- /components/ui/tabs.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib"; 2 | import type { ForwardedRefType, InferProps } from "@/lib/type-helpers"; 3 | import * as TabsPrimitive from "@radix-ui/react-tabs"; 4 | import { forwardRef } from "react"; 5 | 6 | function TabList( 7 | props: InferProps, 8 | ref: ForwardedRefType 9 | ) { 10 | const { className, ...restOfProps } = props; 11 | 12 | return ( 13 | 21 | ); 22 | } 23 | 24 | const TabsTrigger = ( 25 | props: InferProps, 26 | ref: ForwardedRefType 27 | ) => { 28 | const { className, ...restOfProps } = props; 29 | 30 | return ( 31 | 39 | ); 40 | }; 41 | 42 | const TabsContent = ( 43 | props: InferProps, 44 | ref: ForwardedRefType 45 | ) => { 46 | const { className, ...restOfProps } = props; 47 | 48 | return ( 49 | 57 | ); 58 | }; 59 | 60 | const Tabs = { 61 | Root: TabsPrimitive.Root, 62 | List: forwardRef(TabList), 63 | Trigger: forwardRef(TabsTrigger), 64 | Content: forwardRef(TabsContent), 65 | }; 66 | 67 | export default Tabs; 68 | -------------------------------------------------------------------------------- /components/ui/toggle.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib"; 2 | import type { ForwardedRefType, InferProps } from "@/lib/type-helpers"; 3 | import * as TogglePrimitive from "@radix-ui/react-toggle"; 4 | import { type VariantProps, cva } from "class-variance-authority"; 5 | import { forwardRef } from "react"; 6 | 7 | type ToggleProps = InferProps & 8 | VariantProps; 9 | 10 | function Toggle( 11 | props: ToggleProps, 12 | ref: ForwardedRefType 13 | ) { 14 | const { className, variant, size, ...restOfProps } = props; 15 | 16 | return ( 17 | 22 | ); 23 | } 24 | 25 | export default forwardRef(Toggle); 26 | 27 | export const toggleVariants = cva( 28 | "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground", 29 | { 30 | variants: { 31 | variant: { 32 | default: "bg-transparent", 33 | outline: 34 | "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground", 35 | }, 36 | size: { 37 | default: "h-10", 38 | sm: "h-9", 39 | lg: "h-11", 40 | }, 41 | }, 42 | defaultVariants: { 43 | variant: "default", 44 | size: "default", 45 | }, 46 | } 47 | ); 48 | -------------------------------------------------------------------------------- /interfaces/ApiResponses.ts: -------------------------------------------------------------------------------- 1 | import type { Campaign } from "./Campaign"; 2 | 3 | export type User = { 4 | twoFA: { 5 | type: string; 6 | active: boolean; 7 | isVerified: boolean; 8 | }; 9 | _id: string; 10 | firstName: string; 11 | lastName: string; 12 | email: string; 13 | role: string; 14 | isProfileComplete: boolean; 15 | isIdVerified: boolean; 16 | isSuspended: boolean; 17 | isEmailVerified: boolean; 18 | isMobileVerified: boolean; 19 | isTermAndConditionAccepted: boolean; 20 | createdAt: string; 21 | photo: string; 22 | phoneNumber: string; 23 | }; 24 | 25 | export type SessionData = { 26 | user: User; 27 | campaigns: Campaign[]; 28 | }; 29 | 30 | export type ApiResponse> = { 31 | status: string; 32 | message: string; 33 | error?: Record | string; 34 | data?: T; 35 | }; 36 | -------------------------------------------------------------------------------- /interfaces/Campaign.ts: -------------------------------------------------------------------------------- 1 | import type { Donation } from "@/interfaces/Donation"; 2 | import { targetCountries } from "@/lib/helpers/campaign"; 3 | import type { Prettify } from "@/lib/type-helpers"; 4 | 5 | export type Image = Prettify<{ 6 | secureUrl: string; 7 | blurHash: string; 8 | _id: string; 9 | }>; 10 | 11 | type Creator = Prettify<{ 12 | _id: string; 13 | firstName: string; 14 | lastName: string; 15 | photo: string; 16 | }>; 17 | 18 | type Category = Prettify<{ 19 | isDeleted: boolean; 20 | _id: string; 21 | name: string; 22 | createdAt: string; 23 | updatedAt: string; 24 | }>; 25 | 26 | type Fundraiser = "INDIVIDUAL" | "BENEFICIARY"; 27 | 28 | type Status = "In Review" | "Approved" | "Rejected" | "Draft"; 29 | 30 | type FlaggedReasonType = "Inappropriate Content" | "Mismatch" | "Exists"; 31 | 32 | export type Campaign = { 33 | _id: string; 34 | currentStep: 1 | 2 | 3; 35 | shortId: string; 36 | category: Category | null; 37 | country: (typeof targetCountries)[number]; 38 | tags: string[]; 39 | goal: number; 40 | amountRaised: number; 41 | story: string; 42 | storyHtml: string; 43 | images: Image[]; 44 | title: string; 45 | fundraiser: Fundraiser; 46 | deadline: string; 47 | creator: Creator | null; 48 | isPublished: boolean; 49 | status: Status; 50 | isFlagged: boolean; 51 | flaggedReasons: Array<{ type: FlaggedReasonType; reason: string }>; 52 | isDeleted: boolean; 53 | featured: boolean; 54 | donations: Donation[]; 55 | totalDonations: number; 56 | }; 57 | 58 | export type AllCampaignCategories = { 59 | _id: string; 60 | name: string; 61 | count: string; 62 | createdAt: string; 63 | updatedAt: string; 64 | }; 65 | -------------------------------------------------------------------------------- /interfaces/Donation.ts: -------------------------------------------------------------------------------- 1 | export type Donation = { 2 | _id: string; 3 | reference: string; 4 | campaignId: string; 5 | donorEmail: string; 6 | donorName: string; 7 | amount: number; 8 | paymentStatus: string; 9 | paymentDate: string; 10 | paymentMeta?: object; 11 | hideDonorDetails: boolean; 12 | createdAt?: string; 13 | updatedAt?: string; 14 | }; 15 | -------------------------------------------------------------------------------- /interfaces/FormInputs.ts: -------------------------------------------------------------------------------- 1 | export type SignUpProps = { 2 | firstName: string; 3 | lastName: string; 4 | email: string; 5 | password: string; 6 | confirmPassword: string; 7 | terms: boolean; 8 | }; 9 | 10 | export type LoginProps = { 11 | email: string; 12 | password: string; 13 | }; 14 | 15 | export type ResetPasswordProps = { 16 | password: string; 17 | confirmPassword: string; 18 | }; 19 | 20 | export type ForgotPasswordProps = { 21 | email: string; 22 | }; 23 | 24 | export type ContactUsProps = { 25 | firstName: string; 26 | lastName: string; 27 | email: string; 28 | message: string; 29 | }; 30 | 31 | export type UpdateProfileProps = { 32 | firstName?: string; 33 | lastName?: string; 34 | // email?: string; 35 | phoneNumber?: string; 36 | }; 37 | 38 | export type UpdatePasswordsProps = { 39 | oldPassword: string; 40 | newPassword: string; 41 | confirmPassword: string; 42 | }; 43 | 44 | export type CardDetailsProps = { 45 | cardNumber: string; 46 | cvv: string; 47 | cardName: string; 48 | cardExpiry: string; 49 | }; 50 | 51 | export type AddAccountDetailsProps = { 52 | accountName: string; 53 | accountNumber: string; 54 | bankName: string; 55 | }; 56 | 57 | export type DonationDetailsProps = { 58 | donorEmail: string; 59 | donorName: string; 60 | amount: string; 61 | }; 62 | -------------------------------------------------------------------------------- /interfaces/Layouts.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from "react"; 2 | 3 | export interface BaseLayoutProps { 4 | children: ReactNode; 5 | } 6 | 7 | export interface AuthLayoutProps extends BaseLayoutProps { 8 | greeting?: string; 9 | heading?: string; 10 | contentClass?: string; 11 | withHeader: boolean; 12 | title: string; 13 | content: string; 14 | hasSuccess: boolean; 15 | } 16 | -------------------------------------------------------------------------------- /interfaces/SvgProps.ts: -------------------------------------------------------------------------------- 1 | export type FillSvgProps = { 2 | fill?: string | boolean; 3 | stroke?: string | boolean; 4 | }; 5 | -------------------------------------------------------------------------------- /interfaces/WithPageLayout.ts: -------------------------------------------------------------------------------- 1 | import type { NextPage } from "next"; 2 | import type { ReactNode } from "react"; 3 | 4 | export type WithPageLayout = NextPage & { 5 | PageLayout?: React.ComponentType<{ children: ReactNode }>; 6 | }; 7 | -------------------------------------------------------------------------------- /interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export type { ApiResponse, User } from "./ApiResponses"; 2 | export type { 3 | ForgotPasswordProps, 4 | LoginProps, 5 | ResetPasswordProps, 6 | SignUpProps, 7 | ContactUsProps, 8 | UpdateProfileProps, 9 | UpdatePasswordsProps, 10 | CardDetailsProps, 11 | AddAccountDetailsProps, 12 | DonationDetailsProps, 13 | } from "./FormInputs"; 14 | export type { AuthLayoutProps, BaseLayoutProps } from "./Layouts"; 15 | export type { WithPageLayout } from "./WithPageLayout"; 16 | export type { FillSvgProps } from "./SvgProps"; 17 | export type { AllCampaignCategories } from "./Campaign"; 18 | -------------------------------------------------------------------------------- /layouts/AuthPagesLayout.tsx: -------------------------------------------------------------------------------- 1 | import { LogoBanner, PageMetaData } from "@/components/common"; 2 | import type { AuthLayoutProps } from "@/interfaces"; 3 | 4 | export const AuthPagesLayout = ({ 5 | children, 6 | title, 7 | content, 8 | greeting, 9 | heading, 10 | withHeader, 11 | contentClass, 12 | hasSuccess, 13 | }: AuthLayoutProps) => { 14 | return ( 15 |
    16 | 17 |
    18 | {!hasSuccess ? ( 19 |
    25 | 26 | {withHeader && ( 27 |
    28 |

    {heading}

    29 |

    {greeting}

    30 |
    31 | )} 32 | {children} 33 |
    34 | ) : ( 35 |
    {children}
    36 | )} 37 |
    38 |
    39 |
    40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /layouts/BaseLayout.tsx: -------------------------------------------------------------------------------- 1 | import { Footer, Header } from "@/components/common"; 2 | import type { BaseLayoutProps } from "@/interfaces"; 3 | 4 | export const BaseLayout = ({ children }: BaseLayoutProps) => { 5 | return ( 6 | <> 7 |
    8 | {/* */} 15 | {children} 16 |