diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..39cb3268 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,5 @@ +node_modules +coverage +html +dist +!.prettierrc.cjs \ No newline at end of file diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 4f6f59ee..4727f0ce 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,83 +1,68 @@ +// @ts-check + /** - * This is intended to be a basic starting point for linting in your app. - * It relies on recommended configs out of the box for simplicity, but you can - * and should modify this configuration to best suit your team's needs. + * To use this configuration, you need to install the following dependencies: + * + * eslint@^8.57.0 @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-react-refresh eslint-plugin-unicorn eslint-plugin-unused-imports@^3.2.0 prettier eslint-config-prettier eslint-plugin-prettier @ianvs/prettier-plugin-sort-imports prettier-plugin-tailwindcss + * + * + * To Replicate the vitest configuration, you need to install the following dependencies: + * + * eslint-plugin-vitest@^0.4.1 eslint-testing-library + * + * Also replicate the .prettierrc.cjs file in the root of your project. */ /** @type {import('eslint').Linter.Config} */ module.exports = { root: true, - parserOptions: { - ecmaVersion: "latest", - sourceType: "module", - ecmaFeatures: { - jsx: true, - }, - }, + reportUnusedDisableDirectives: true, env: { browser: true, - commonjs: true, - es6: true, + es2020: true, }, - ignorePatterns: ["!**/.server", "!**/.client"], - - // Base config - extends: ["eslint:recommended"], - - overrides: [ - // React - { - files: ["**/*.{js,jsx,ts,tsx}"], - plugins: ["react", "jsx-a11y"], - extends: [ - "plugin:react/recommended", - "plugin:react/jsx-runtime", - "plugin:react-hooks/recommended", - "plugin:jsx-a11y/recommended", - ], - settings: { - react: { - version: "detect", - }, - formComponents: ["Form"], - linkComponents: [ - { name: "Link", linkAttribute: "to" }, - { name: "NavLink", linkAttribute: "to" }, - ], - "import/resolver": { - typescript: {}, - }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:react/jsx-runtime", + "plugin:@typescript-eslint/recommended", + "plugin:react-hooks/recommended", + "plugin:unicorn/recommended", + "plugin:prettier/recommended", + ], + ignorePatterns: ["dist", "node_modules"], + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint", "react", "unicorn", "unused-imports"], + rules: { + "react/prop-types": "off", + "unused-imports/no-unused-imports": "error", + "unused-imports/no-unused-vars": [ + "warn", + { + vars: "all", + varsIgnorePattern: "^_", + args: "after-used", + argsIgnorePattern: "^_", }, - }, - - // Typescript + ], + "unicorn/filename-case": [ + "error", + { cases: { kebabCase: true, pascalCase: true, camelCase: true } }, + ], + }, + settings: { + react: { version: "detect" }, + vitest: { typecheck: true }, + }, + overrides: [ { - files: ["**/*.{ts,tsx}"], - plugins: ["@typescript-eslint", "import"], - parser: "@typescript-eslint/parser", - settings: { - "import/internal-regex": "^~/", - "import/resolver": { - node: { - extensions: [".ts", ".tsx"], - }, - typescript: { - alwaysTryTypes: true, - }, - }, - }, - extends: [ - "plugin:@typescript-eslint/recommended", - "plugin:import/recommended", - "plugin:import/typescript", - ], + files: [".eslintrc.*js", ".vite(|st).(js|ts)"], + env: { node: true }, }, - - // Node { - files: [".eslintrc.cjs"], - env: { - node: true, + files: ["*.d.ts"], + rules: { + "unicorn/prevent-abbreviations": "off", }, }, ], diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 00000000..d7afe15e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,38 @@ +name: Feature +description: An enhancement or feature +title: "[Feature]: " +labels: ["triage", "feature"] +body: + - type: textarea + id: description + attributes: + label: Description + description: A step-by-step description of the suggested feature/enhancement. + placeholder: On the user page, you should be able to... + validations: + required: true + - type: textarea + id: acceptanceCriteria + attributes: + label: Acceptance Criteria + description: What are the things that must be achieved for your ticket to be considered complete. + validations: + required: true + - type: markdown + attributes: + value: > + | Please include any screenshots which would help demonstrate the steps + and point out which parts the feature is related to + - type: textarea + id: links + attributes: + label: Links + description: Place links to supporting docs here. e.g. Figma + value: > + | [`FIGMA LINK`](LINK_HERE) + - type: textarea + id: images + attributes: + label: Images + description: Paste images or image urls + value: "![image](URL_HERE)" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..ccb2a022 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,47 @@ + + +# Description + + + + + +**Closes #issue_number_here** + +# Changes proposed + +## What were you told to do? + + + +## What did you do? + + + +# Check List (Check all the applicable boxes) + +🚨Please review the [contribution guideline](CONTRIBUTING.md) for this repository. + + + + + +- [] My code follows the code style of this project. +- [] This PR does not contain plagiarized content. +- [] The title and description of the PR is clear and explains the approach. +- [] I am making a pull request against the **dev branch** (left side). +- [] My commit messages styles matches our requested structure. +- [] My code additions will fail neither code linting checks nor unit test. +- [] I am only making changes to files I was requested to. + +# Screenshots/Videos + + + + diff --git a/.github/workflows/initial-label.yml b/.github/workflows/initial-label.yml new file mode 100644 index 00000000..a091548e --- /dev/null +++ b/.github/workflows/initial-label.yml @@ -0,0 +1,18 @@ +name: Label new issues +on: + issues: + types: + - reopened + - opened +jobs: + label_issues: + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - run: gh issue edit "$NUMBER" --add-label "$LABELS" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.issue.number }} + LABELS: triage diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..8bb63d2a --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,21 @@ +name: Lint + +on: + pull_request: + +jobs: + eslint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + - uses: pnpm/action-setup@v4 + with: + version: 9 + - run: pnpm install + - uses: reviewdog/action-eslint@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + eslint_flags: ". --ext js,jsx,ts,tsx --ignore-path=.gitignore" diff --git a/.gitignore b/.gitignore index 80ec311f..5b531e0e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules +/.react-email /.cache /build diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 00000000..a9a84453 --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1,22 @@ +/** @type {import('prettier').Config & import("@ianvs/prettier-plugin-sort-imports").PluginConfig} */ +module.exports = { + tabWidth: 2, + printWidth: 80, + jsxSingleQuote: false, + singleQuote: false, + semi: true, + trailingComma: "all", + arrowParens: "always", + endOfLine: "auto", + + plugins: [ + "@ianvs/prettier-plugin-sort-imports", + "prettier-plugin-tailwindcss", + ], + + // #region @ianvs/prettier-plugin-sort-imports + importOrder: ["", "", "^~/", "^[.][.]/", "^[.]/"], + importOrderParserPlugins: ["typescript", "jsx", "decorators-legacy"], + importOrderTypeScriptVersion: "5.0.0", + // #endregion @ianvs/prettier-plugin-sort-imports +}; diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..897af65d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..a62dbfe3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "[javascript][javascriptreact][typescript][typescriptreact]": { + "editor.formatOnSave": false, + "editor.defaultFormatter": "vscode.typescript-language-features" + }, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "always" + }, +} \ No newline at end of file diff --git a/app/components/index.ts b/app/components/index.ts index e69de29b..cb0ff5c3 100644 --- a/app/components/index.ts +++ b/app/components/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/app/components/ui/DataCard.tsx b/app/components/ui/DataCard.tsx index 45d372b9..9d15af17 100644 --- a/app/components/ui/DataCard.tsx +++ b/app/components/ui/DataCard.tsx @@ -1,28 +1,25 @@ -import { ReactNode } from 'react' -type DataCardType = { - title: string, - amount: string, - subText: string, - icon: ReactNode, -} +import { ReactNode } from "react"; +type DataCardType = { + title: string; + amount: string; + subText: string; + icon: ReactNode; +}; const DataCard = ({ title, amount, subText, icon }: DataCardType) => { - return ( - -
- -
-

{title}

- {icon} -
-
-

${amount}

-

{subText}

-
- -
- ) -} + return ( +
+
+

{title}

+ {icon} +
+
+

${amount}

+

{subText}

+
+
+ ); +}; -export default DataCard +export default DataCard; diff --git a/app/components/ui/alert-dialog.tsx b/app/components/ui/alert-dialog.tsx index a1c212ee..7044fe66 100644 --- a/app/components/ui/alert-dialog.tsx +++ b/app/components/ui/alert-dialog.tsx @@ -1,130 +1,134 @@ -"use client" +"use client"; -import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; +import { buttonVariants } from "app/components/ui/button"; +import { cn } from "app/lib/utils/cn"; +import { + ComponentPropsWithoutRef, + ElementRef, + forwardRef, + HTMLAttributes, +} from "react"; -import { cn } from "app/lib/utils/cn" -import { buttonVariants } from "app/components/ui/button" -import { ComponentPropsWithoutRef, ElementRef, forwardRef, HTMLAttributes } from "react" +const AlertDialog = AlertDialogPrimitive.Root; -const AlertDialog = AlertDialogPrimitive.Root +const AlertDialogTrigger = AlertDialogPrimitive.Trigger; -const AlertDialogTrigger = AlertDialogPrimitive.Trigger - -const AlertDialogPortal = AlertDialogPrimitive.Portal +const AlertDialogPortal = AlertDialogPrimitive.Portal; const AlertDialogOverlay = forwardRef< ElementRef, ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => ( -)) -AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName +)); +AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName; const AlertDialogContent = forwardRef< ElementRef, ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => ( -)) -AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName +)); +AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; const AlertDialogHeader = ({ className, - ...props + ...properties }: HTMLAttributes) => (
-) -AlertDialogHeader.displayName = "AlertDialogHeader" +); +AlertDialogHeader.displayName = "AlertDialogHeader"; const AlertDialogFooter = ({ className, - ...props + ...properties }: HTMLAttributes) => (
-) -AlertDialogFooter.displayName = "AlertDialogFooter" +); +AlertDialogFooter.displayName = "AlertDialogFooter"; const AlertDialogTitle = forwardRef< ElementRef, ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => ( -)) -AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName +)); +AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName; const AlertDialogDescription = forwardRef< ElementRef, ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => ( -)) +)); AlertDialogDescription.displayName = - AlertDialogPrimitive.Description.displayName + AlertDialogPrimitive.Description.displayName; const AlertDialogAction = forwardRef< ElementRef, ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => ( -)) -AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName +)); +AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; const AlertDialogCancel = forwardRef< ElementRef, ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => ( -)) -AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName +)); +AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; export { AlertDialog, @@ -138,4 +142,4 @@ export { AlertDialogDescription, AlertDialogAction, AlertDialogCancel, -} +}; diff --git a/app/components/ui/button.tsx b/app/components/ui/button.tsx index 59ea2b11..1e269149 100644 --- a/app/components/ui/button.tsx +++ b/app/components/ui/button.tsx @@ -1,8 +1,7 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "app/lib/utils/cn" +import { Slot } from "@radix-ui/react-slot"; +import { cn } from "app/lib/utils/cn"; +import { cva, type VariantProps } from "class-variance-authority"; +import * as React from "react"; const buttonVariants = cva( "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", @@ -30,27 +29,27 @@ const buttonVariants = cva( variant: "default", size: "default", }, - } -) + }, +); -export interface ButtonProps +export interface ButtonProperties extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean + VariantProps { + asChild?: boolean; } -const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button" +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...properties }, reference) => { + const Comp = asChild ? Slot : "button"; return ( - ) - } -) -Button.displayName = "Button" + ); + }, +); +Button.displayName = "Button"; -export { Button, buttonVariants } +export { Button, buttonVariants }; diff --git a/app/components/ui/card.tsx b/app/components/ui/card.tsx index aea49b04..77b80c1b 100644 --- a/app/components/ui/card.tsx +++ b/app/components/ui/card.tsx @@ -1,80 +1,85 @@ -import { cn } from "app/lib/utils/cn" -import { forwardRef, HTMLAttributes } from "react" +import { cn } from "app/lib/utils/cn"; +import { forwardRef, HTMLAttributes } from "react"; -const Card = forwardRef< - HTMLDivElement, - HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -Card.displayName = "Card" +const Card = forwardRef>( + ({ className, ...properties }, reference) => ( +
+ ), +); +Card.displayName = "Card"; -const CardHeader = forwardRef< - HTMLDivElement, - HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardHeader.displayName = "CardHeader" +const CardHeader = forwardRef>( + ({ className, ...properties }, reference) => ( +
+ ), +); +CardHeader.displayName = "CardHeader"; const CardTitle = forwardRef< HTMLParagraphElement, HTMLAttributes ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => (

- Title -

-)) -CardTitle.displayName = "CardTitle" + {...properties} + /> +)); +CardTitle.displayName = "CardTitle"; const CardDescription = forwardRef< HTMLParagraphElement, HTMLAttributes ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => (

-)) -CardDescription.displayName = "CardDescription" +)); +CardDescription.displayName = "CardDescription"; -const CardContent = forwardRef< - HTMLDivElement, - HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardContent.displayName = "CardContent" +const CardContent = forwardRef>( + ({ className, ...properties }, reference) => ( +
+ ), +); +CardContent.displayName = "CardContent"; -const CardFooter = forwardRef< - HTMLDivElement, - HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardFooter.displayName = "CardFooter" +const CardFooter = forwardRef>( + ({ className, ...properties }, reference) => ( +
+ ), +); +CardFooter.displayName = "CardFooter"; -export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardDescription, + CardContent, +}; diff --git a/app/components/ui/card/card-platform.tsx b/app/components/ui/card/card-platform.tsx index d89c28d6..cf20fa37 100644 --- a/app/components/ui/card/card-platform.tsx +++ b/app/components/ui/card/card-platform.tsx @@ -1,55 +1,79 @@ import { useState } from "react"; + import { cn } from "~/lib/utils/cn"; -type PlatformCardProps = { - /** - * Displaying the platform name or title. - */ - heading: string; +type PlatformCardProperties = { + /** + * Displaying the platform name or title. + */ + heading: string; - /** - * Displaying the platform logo or icon. - */ - logo: string; - /** - * Providing a brief overview of the platform. - */ - description: string; - /** - * Additional class names for customizing the container style. - */ - containerClassName?: string; + /** + * Displaying the platform logo or icon. + */ + logo: string; + /** + * Providing a brief overview of the platform. + */ + description: string; + /** + * Additional class names for customizing the container style. + */ + containerClassName?: string; }; /** * A card component that displays platform details including a heading, logo, description, and a toggle switch. * The toggle switch allows admins to activate or deactivate the platform. - * + * * @param {PlatformCardProps} props - The properties for the component. * @returns The CardPlatform component. */ -export default function CardPlatform({ heading, logo, description, containerClassName }: PlatformCardProps) { - - const [isActivated, setIsActivated] = useState(false) +export default function CardPlatform({ + heading, + logo, + description, + containerClassName, +}: PlatformCardProperties) { + const [isActivated, setIsActivated] = useState(false); - const toggleSwitchHandler = () => setIsActivated(prev => !prev) + const toggleSwitchHandler = () => setIsActivated((previous) => !previous); - return ( -
-
-
- {heading} -
- -
-
-

{heading}

-

{description}

-
-
- ); -} \ No newline at end of file + return ( +
+
+
+ {heading} +
+ +
+
+

+ {heading} +

+

{description}

+
+
+ ); +} diff --git a/app/components/ui/input.tsx b/app/components/ui/input.tsx index d03682ef..1a8ff0d3 100644 --- a/app/components/ui/input.tsx +++ b/app/components/ui/input.tsx @@ -1,25 +1,24 @@ -import * as React from "react" +import { cn } from "app/lib/utils/cn"; +import * as React from "react"; -import { cn } from "app/lib/utils/cn" - -export interface InputProps +export interface InputProperties extends React.InputHTMLAttributes {} -const Input = React.forwardRef( - ({ className, type, ...props }, ref) => { +const Input = React.forwardRef( + ({ className, type, ...properties }, reference) => { return ( - ) - } -) -Input.displayName = "Input" + ); + }, +); +Input.displayName = "Input"; -export { Input } +export { Input }; diff --git a/app/components/ui/label.tsx b/app/components/ui/label.tsx index b16292da..8764b186 100644 --- a/app/components/ui/label.tsx +++ b/app/components/ui/label.tsx @@ -1,26 +1,25 @@ -"use client" +"use client"; -import * as React from "react" -import * as LabelPrimitive from "@radix-ui/react-label" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "app/lib/utils/cn" +import * as LabelPrimitive from "@radix-ui/react-label"; +import { cn } from "app/lib/utils/cn"; +import { cva, type VariantProps } from "class-variance-authority"; +import * as React from "react"; const labelVariants = cva( - "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" -) + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", +); const Label = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & VariantProps ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => ( -)) -Label.displayName = LabelPrimitive.Root.displayName +)); +Label.displayName = LabelPrimitive.Root.displayName; -export { Label } +export { Label }; diff --git a/app/components/ui/tabs.tsx b/app/components/ui/tabs.tsx index ba541f05..61abb7b0 100644 --- a/app/components/ui/tabs.tsx +++ b/app/components/ui/tabs.tsx @@ -1,55 +1,54 @@ -"use client" +"use client"; -import * as TabsPrimitive from "@radix-ui/react-tabs" +import * as TabsPrimitive from "@radix-ui/react-tabs"; +import { cn } from "app/lib/utils/cn"; +import { ComponentPropsWithoutRef, ElementRef, forwardRef } from "react"; -import { cn } from "app/lib/utils/cn" -import { ComponentPropsWithoutRef, ElementRef, forwardRef } from "react" - -const Tabs = TabsPrimitive.Root +const Tabs = TabsPrimitive.Root; const TabsList = forwardRef< ElementRef, ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => ( -)) -TabsList.displayName = TabsPrimitive.List.displayName +)); +TabsList.displayName = TabsPrimitive.List.displayName; const TabsTrigger = forwardRef< ElementRef, ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => ( -)) -TabsTrigger.displayName = TabsPrimitive.Trigger.displayName +)); +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName; const TabsContent = forwardRef< ElementRef, ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className, ...properties }, reference) => ( -)) -TabsContent.displayName = TabsPrimitive.Content.displayName +)); +TabsContent.displayName = TabsPrimitive.Content.displayName; -export { Tabs, TabsList, TabsTrigger, TabsContent } +export { Tabs, TabsList, TabsTrigger, TabsContent }; diff --git a/app/email/templates/_components/tailwindWrapper.tsx b/app/email/templates/_components/tailwindWrapper.tsx new file mode 100644 index 00000000..0d0c8280 --- /dev/null +++ b/app/email/templates/_components/tailwindWrapper.tsx @@ -0,0 +1,14 @@ +import { Tailwind } from "@react-email/components"; +import React from "react"; + +import TailwindConfig from "../../../../tailwind.config"; + +interface Properties { + children: React.ReactNode; +} + +export default function TailwindWrapper(properties: Properties) { + const { children } = properties; + + return {children}; +} diff --git a/app/email/templates/password-reset/no-image.tsx b/app/email/templates/password-reset/no-image.tsx new file mode 100644 index 00000000..d3156be5 --- /dev/null +++ b/app/email/templates/password-reset/no-image.tsx @@ -0,0 +1,32 @@ +import { Button, Head, Html, Preview, Text } from "@react-email/components"; + +import Tailwindwrapper from "~/email/templates/_components/tailwindWrapper"; + +interface IProperties { + name: string; +} + +export default function Email(properties: IProperties) { + const { name } = properties; + + return ( + + + {`Password Reset for ${name}`} + + + Hi there, {name}! + + + + ); +} + +Email.PreviewProps = { + name: "John Doe", +} satisfies IProperties; diff --git a/app/email/templates/welcome/no-image.tsx b/app/email/templates/welcome/no-image.tsx new file mode 100644 index 00000000..dd1e09e1 --- /dev/null +++ b/app/email/templates/welcome/no-image.tsx @@ -0,0 +1,32 @@ +import { Button, Head, Html, Preview, Text } from "@react-email/components"; + +import Tailwindwrapper from "~/email/templates/_components/tailwindWrapper"; + +interface IProperties { + name: string; +} + +export default function Email(properties: IProperties) { + const { name } = properties; + + return ( + + + {`Welcome ${name}`} + + + Hi there, {name}! + + + + ); +} + +Email.PreviewProps = { + name: "John Doe", +} satisfies IProperties; diff --git a/app/entry.client.tsx b/app/entry.client.tsx index 94d5dc0d..61291328 100644 --- a/app/entry.client.tsx +++ b/app/entry.client.tsx @@ -13,6 +13,6 @@ startTransition(() => { document, - + , ); }); diff --git a/app/entry.server.tsx b/app/entry.server.tsx index 45db3229..d1ca790c 100644 --- a/app/entry.server.tsx +++ b/app/entry.server.tsx @@ -5,14 +5,16 @@ */ import { PassThrough } from "node:stream"; - -import type { AppLoadContext, EntryContext } from "@remix-run/node"; -import { createReadableStreamFromReadable } from "@remix-run/node"; +import { + createReadableStreamFromReadable, + type AppLoadContext, + type EntryContext, +} from "@remix-run/node"; import { RemixServer } from "@remix-run/react"; import { isbot } from "isbot"; import { renderToPipeableStream } from "react-dom/server"; -const ABORT_DELAY = 5_000; +const ABORT_DELAY = 5000; export default function handleRequest( request: Request, @@ -22,20 +24,20 @@ export default function handleRequest( // This is ignored so we can keep it in the template for visibility. Feel // free to delete this parameter in your app if you're not using it! // eslint-disable-next-line @typescript-eslint/no-unused-vars - loadContext: AppLoadContext + _loadContext: AppLoadContext, ) { return isbot(request.headers.get("user-agent") || "") ? handleBotRequest( request, responseStatusCode, responseHeaders, - remixContext + remixContext, ) : handleBrowserRequest( request, responseStatusCode, responseHeaders, - remixContext + remixContext, ); } @@ -43,7 +45,7 @@ function handleBotRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, - remixContext: EntryContext + remixContext: EntryContext, ) { return new Promise((resolve, reject) => { let shellRendered = false; @@ -65,7 +67,7 @@ function handleBotRequest( new Response(stream, { headers: responseHeaders, status: responseStatusCode, - }) + }), ); pipe(body); @@ -82,7 +84,7 @@ function handleBotRequest( console.error(error); } }, - } + }, ); setTimeout(abort, ABORT_DELAY); @@ -93,7 +95,7 @@ function handleBrowserRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, - remixContext: EntryContext + remixContext: EntryContext, ) { return new Promise((resolve, reject) => { let shellRendered = false; @@ -115,7 +117,7 @@ function handleBrowserRequest( new Response(stream, { headers: responseHeaders, status: responseStatusCode, - }) + }), ); pipe(body); @@ -132,7 +134,7 @@ function handleBrowserRequest( console.error(error); } }, - } + }, ); setTimeout(abort, ABORT_DELAY); diff --git a/app/lib/utils/cn.ts b/app/lib/utils/cn.ts index 365058ce..a5ef1935 100644 --- a/app/lib/utils/cn.ts +++ b/app/lib/utils/cn.ts @@ -1,4 +1,4 @@ -import { type ClassValue, clsx } from "clsx"; +import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { diff --git a/app/root.tsx b/app/root.tsx index 8253a92c..0b76e794 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,3 +1,5 @@ +import { cssBundleHref } from "@remix-run/css-bundle"; +import { LinksFunction } from "@remix-run/node"; import { Links, Meta, @@ -5,9 +7,8 @@ import { Scripts, ScrollRestoration, } from "@remix-run/react"; -import { LinksFunction } from "@remix-run/node"; + import styles from "./styles/global.css?url"; -import { cssBundleHref } from "@remix-run/css-bundle"; export const links: LinksFunction = () => [ { rel: "stylesheet", href: styles }, diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index 1eeb5b2f..4cc46675 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -1,4 +1,5 @@ import type { MetaFunction } from "@remix-run/node"; + import { Button } from "~/components/ui/button"; import CardPlatform from "~/components/ui/card/card-platform"; @@ -11,9 +12,9 @@ export const meta: MetaFunction = () => { export default function Index() { return ( -
+

Welcome to Remix

-