diff --git a/dashboard/src/features/sidebar/sidebar.tsx b/dashboard/src/features/sidebar/sidebar.tsx index 0f3e155..e4488a3 100644 --- a/dashboard/src/features/sidebar/sidebar.tsx +++ b/dashboard/src/features/sidebar/sidebar.tsx @@ -5,11 +5,9 @@ import { import { useIsCurrentRoute } from "@marzneshin/hooks"; import type { FC } from "react"; import { sidebarItems as sidebarItemsSudoAdmin, sidebarItemsNonSudoAdmin } from "."; -import { cn } from "@marzneshin/utils"; +import { projectInfo, cn } from "@marzneshin/utils"; import { useAuth } from "@marzneshin/features/auth"; -import { - SupportUs, -} from "@marzneshin/features/support-us"; +import { SupportUs } from "@marzneshin/features/support-us"; interface DashboardSidebarProps { collapsed: boolean; @@ -57,9 +55,9 @@ export const DashboardSidebar: FC = ({ {collapsed ? - + : - + } diff --git a/dashboard/src/features/support-us/card.tsx b/dashboard/src/features/support-us/card.tsx new file mode 100644 index 0000000..dc50284 --- /dev/null +++ b/dashboard/src/features/support-us/card.tsx @@ -0,0 +1,47 @@ +import type { FC, HTMLAttributes } from "react"; +import { SupportUsVariation } from "./types"; +import { X, HeartHandshake } from "lucide-react"; +import { Button, Card, CardTitle, CardContent } from "@marzneshin/components"; +import { cn } from "@marzneshin/utils"; +import { useTranslation } from "react-i18next"; + +export interface SupportUsCardProps extends HTMLAttributes { + variant?: SupportUsVariation; + donationLink: string; + setSupportUsOpen: (state: boolean) => void; +} + +export const SupportUsCard: FC = ({ className, variant, setSupportUsOpen, donationLink }) => { + const { t } = useTranslation(); + return ( + + + +
+ {t('support-us.title')} +
+ {variant !== "view" && ( + + )} +
+

{t('support-us.desc')}

+ +
+
+ ); +} diff --git a/dashboard/src/features/support-us/donation-button.tsx b/dashboard/src/features/support-us/donation-button.tsx new file mode 100644 index 0000000..a13855d --- /dev/null +++ b/dashboard/src/features/support-us/donation-button.tsx @@ -0,0 +1,18 @@ +import { useTranslation } from "react-i18next"; +import { Button } from "@marzneshin/components"; +import type { FC } from "react"; + +export const DonationButton: FC<{ donationLink: string }> = ({ donationLink }) => { + const { t } = useTranslation(); + return ( + + ) +} diff --git a/dashboard/src/features/support-us/index.tsx b/dashboard/src/features/support-us/index.tsx index 3735c18..5d00b4f 100644 --- a/dashboard/src/features/support-us/index.tsx +++ b/dashboard/src/features/support-us/index.tsx @@ -1,80 +1,31 @@ -import { X, HeartHandshake } from "lucide-react"; -import { Button, Card, CardTitle, CardContent, PopoverTrigger, Popover, PopoverContent } from "@marzneshin/components"; import { type FC, type HTMLAttributes } from "react"; -import { cn } from "@marzneshin/utils"; -import { useTranslation } from "react-i18next"; import { SupportUsVariation, SupportUsStructure } from "./types"; import { useSupportUs } from "./use-support-us"; +import { SupportUsCard } from "./card"; +import { SupportUsPopover } from "./popover"; export interface SupportUsProps extends HTMLAttributes { + donationLink: string; open?: boolean; variant?: SupportUsVariation; structure?: SupportUsStructure; } -export const SupportUs: FC = ({ open = true, variant = "status", className, structure = "card" }) => { +export const SupportUs: FC = ({ open = true, variant = "status", className, structure = "card", donationLink }) => { const [supportUsOpen, setSupportUsOpen] = useSupportUs(variant, open); - const { t } = useTranslation(); - - const CardStructure = () => ( - - - -
- {t('support-us.title')} -
- {variant !== "view" && ( - - )} -
-

{t('support-us.desc')}

- -
-
- ); - - const PopoverStructure = () => ( - - - - - -
-
- {t('support-us.title')} -
-
-

{t('support-us.desc')}

- -
-
- ); if (!supportUsOpen) return null; - return structure === "popover" ? : ; + return structure === "popover" ? ( + + ) : ( + + ); }; diff --git a/dashboard/src/features/support-us/popover.tsx b/dashboard/src/features/support-us/popover.tsx new file mode 100644 index 0000000..d343f47 --- /dev/null +++ b/dashboard/src/features/support-us/popover.tsx @@ -0,0 +1,33 @@ +import { HeartHandshake } from "lucide-react"; +import { Button, PopoverTrigger, Popover, PopoverContent } from "@marzneshin/components"; +import { type FC, type HTMLAttributes } from "react"; +import { cn } from "@marzneshin/utils"; +import { useTranslation } from "react-i18next"; +import { DonationButton } from "./donation-button"; + +export interface SupportUsPopoverProps extends HTMLAttributes { + donationLink: string; +} + +export const SupportUsPopover: FC = ({ className, donationLink }) => { + const { t } = useTranslation(); + return ( + + + + + +
+
+ {t('support-us.title')} +
+
+

{t('support-us.desc')}

+ +
+
+ ); +} + diff --git a/dashboard/src/features/support-us/support-us.stories.tsx b/dashboard/src/features/support-us/support-us.stories.tsx index 1d77331..b88af17 100644 --- a/dashboard/src/features/support-us/support-us.stories.tsx +++ b/dashboard/src/features/support-us/support-us.stories.tsx @@ -11,7 +11,7 @@ const meta: Meta = { export default meta; type Story = StoryObj; - +const donationLink = "https://localhost.com/donation"; /** * This variation does not provide X button to close the card. @@ -19,7 +19,8 @@ type Story = StoryObj; export const View: Story = { args: { open: true, - variant: "view" + variant: "view", + donationLink } } @@ -31,7 +32,9 @@ export const View: Story = { export const LocalStorage: Story = { args: { open: true, - variant: "local-storage" + variant: "local-storage", + donationLink + } } @@ -43,7 +46,8 @@ export const LocalStorage: Story = { export const Status: Story = { args: { open: true, - variant: "status" + variant: "status", + donationLink } } @@ -54,8 +58,8 @@ Status.play = async ({ canvasElement }) => { await expect(canvas.getByText(/Support Us/i)).toBeInTheDocument(); // Check the Donation link - const donationLink = canvas.getByRole('link', { name: /donate/i }); - await expect(donationLink).toHaveAttribute('href', 'https://github.com/khodedawsh/marzneshin#donation'); + const donationLinkButton = canvas.getByRole('link', { name: /donate/i }); + await expect(donationLinkButton).toHaveAttribute('href', donationLink); // Simulate closing the support card const closeButton = canvas.getByRole('button', { name: /Close/i }); diff --git a/dashboard/src/features/support-us/support-us.test.tsx b/dashboard/src/features/support-us/support-us.test.tsx index f2b39fb..29c4fb3 100644 --- a/dashboard/src/features/support-us/support-us.test.tsx +++ b/dashboard/src/features/support-us/support-us.test.tsx @@ -11,10 +11,12 @@ vi.mock('./use-support-us', () => ({ const useSupportUs = originalUseSupportUs as unknown as ReturnType; describe('SupportUs Component', () => { + const donationLink = "https://localhost.com/donation"; + it('renders the SupportUs component when localStorage is true', () => { useSupportUs.mockReturnValue([true, vi.fn()]); - render(); + render(); expect(screen.getByText(/support-us.title/i)).toBeInTheDocument(); expect(screen.getByText(/support-us.desc/i)).toBeInTheDocument(); @@ -24,7 +26,7 @@ describe('SupportUs Component', () => { it('does not render the SupportUs component when localStorage is false', () => { useSupportUs.mockReturnValue([false, vi.fn()]); - render(); + render(); expect(screen.queryByText(/support-us.title/i)).not.toBeInTheDocument(); }); @@ -33,7 +35,7 @@ describe('SupportUs Component', () => { const setSupportUsOpen = vi.fn(); useSupportUs.mockReturnValue([true, setSupportUsOpen]); - render(); + render(); const closeButton = screen.getByRole('button', { name: /Close/i }); fireEvent.mouseDown(closeButton); @@ -42,7 +44,7 @@ describe('SupportUs Component', () => { }); it('renders the SupportUs component in view mode without close button', () => { - render(); + render(); expect(screen.getByText(/support-us.title/i)).toBeInTheDocument(); expect(screen.queryByRole('button', { name: /Close/i })).not.toBeInTheDocument(); @@ -51,9 +53,9 @@ describe('SupportUs Component', () => { it('redirects to the donation link when the donation button is clicked', () => { useSupportUs.mockReturnValue([true, vi.fn()]); - render(); + render(); - const donationLink = screen.getByRole('link', { name: /support-us.donate/i }); - expect(donationLink).toHaveAttribute('href', 'https://github.com/khodedawsh/marzneshin#donation'); + const donationLinkButton = screen.getByRole('link', { name: /support-us.donate/i }); + expect(donationLinkButton).toHaveAttribute('href', donationLink); }); });