Merged in feat/SW-104-add-card (pull request #410)

Feat/SW-104 add card

* feat: add api endpoints for adding and removing credit card

* feat(SW-104): Added Sonner toast lib

* feat(SW-104): Add route handlers for add card flow

* feat(SW-104): Added link to route handler and trigger toast when query params from callback is set

* feat(SW-104): Added translations for add card success toast

* feat(SW-104): Refactored to use client request for initiate save card

* fix(SW-104): Return proper status codes when initiating save card fails

* fix(SW-104): remove delete card endpoint because it was added in SW-245

* fix(SW-104): remove console.log

* fix(SW-104): Use api.post for save card request

* fix(SW-104): move function declaration above export

* fix(SW-104): handle response of save card and use Lang enum

* fix(SW-104): added comment for why setTimeout is needed for toast and also removed lang prop

* fix(SW-104): added type for AddCreditCardButton props

* feat: add toasts

* fix(SW-104): start using toasts from ToastHandler and fix problem with duplicate toasts

* fix(SW-104): remove unnecessary wrapping div


Approved-by: Michael Zetterberg
This commit is contained in:
Tobias Johansson
2024-08-20 15:04:02 +00:00
parent aa9e723cb5
commit 84f5e74f00
30 changed files with 537 additions and 15 deletions

View File

@@ -0,0 +1,96 @@
import { ExternalToast, toast as sonnerToast, Toaster } from "sonner"
import {
CheckCircleIcon,
CloseLarge,
CrossCircle,
InfoCircleIcon,
WarningTriangle,
} from "@/components/Icons"
import Button from "../Button"
import Body from "../Text/Body"
import { ToastsProps } from "./toasts"
import { toastVariants } from "./variants"
import styles from "./toasts.module.css"
export function ToastHandler() {
return <Toaster />
}
function getIcon(variant: ToastsProps["variant"]) {
switch (variant) {
case "error":
return CrossCircle
case "info":
return InfoCircleIcon
case "success":
return CheckCircleIcon
case "warning":
return WarningTriangle
}
}
export function Toast({ message, onClose, variant }: ToastsProps) {
const className = toastVariants({ variant })
const Icon = getIcon(variant)
return (
<div className={className}>
<div className={styles.iconContainer}>
{Icon && <Icon color="white" height={24} width={24} />}
</div>
<Body className={styles.message}>{message}</Body>
<Button onClick={onClose} variant="icon" intent="text">
<CloseLarge />
</Button>
</div>
)
}
export const toast = {
success: (message: string, options?: ExternalToast) =>
sonnerToast.custom(
(t) => (
<Toast
variant="success"
message={message}
onClose={() => sonnerToast.dismiss(t)}
/>
),
options
),
info: (message: string, options?: ExternalToast) =>
sonnerToast.custom(
(t) => (
<Toast
variant="info"
message={message}
onClose={() => sonnerToast.dismiss(t)}
/>
),
options
),
error: (message: string, options?: ExternalToast) =>
sonnerToast.custom(
(t) => (
<Toast
variant="error"
message={message}
onClose={() => sonnerToast.dismiss(t)}
/>
),
options
),
warning: (message: string, options?: ExternalToast) =>
sonnerToast.custom(
(t) => (
<Toast
variant="warning"
message={message}
onClose={() => sonnerToast.dismiss(t)}
/>
),
options
),
}

View File

@@ -0,0 +1,38 @@
.toast {
display: grid;
grid-template-columns: auto 1fr auto;
border-radius: var(--Corner-radius-Large);
overflow: hidden;
background: var(--Base-Surface-Primary-light-Normal);
box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.08);
align-items: center;
width: var(--width);
}
.message {
padding: var(--Spacing-x2) var(--Spacing-x-one-and-half);
}
.success {
--icon-background-color: var(--UI-Semantic-Success);
}
.error {
--icon-background-color: var(--UI-Semantic-Error);
}
.warning {
--icon-background-color: var(--UI-Semantic-Warning);
}
.info {
--icon-background-color: var(--UI-Semantic-Information);
}
.iconContainer {
display: flex;
background-color: var(--icon-background-color);
padding: var(--Spacing-x2);
align-items: center;
justify-content: center;
}

View File

@@ -0,0 +1,10 @@
import { toastVariants } from "./variants"
import type { VariantProps } from "class-variance-authority"
export interface ToastsProps
extends Omit<React.AnchorHTMLAttributes<HTMLDivElement>, "color">,
VariantProps<typeof toastVariants> {
message: string
onClose: () => void
}

View File

@@ -0,0 +1,14 @@
import { cva } from "class-variance-authority"
import styles from "./toasts.module.css"
export const toastVariants = cva(styles.toast, {
variants: {
variant: {
success: styles.success,
info: styles.info,
warning: styles.warning,
error: styles.error,
},
},
})