refactor: rename navigation function and update sidebar component
- Renamed `getNavMainLinks` to `getSidebarLinks` for improved clarity in the configuration file. - Updated the `DashboardSidebar` component to utilize the new `getSidebarLinks` function and integrated `useCurrentUser` for user status handling. - Enhanced the sidebar to conditionally display the upgrade card and user profile based on membership status. - Updated comments for better understanding of the code functionality.
This commit is contained in:
parent
b5699b85f1
commit
9dbe79593e
@ -11,20 +11,22 @@ import {
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem
|
||||
} from '@/components/ui/sidebar';
|
||||
import { getNavMainLinks } from '@/config';
|
||||
import { getSidebarLinks } from '@/config';
|
||||
import { useCurrentUser } from '@/hooks/use-current-user';
|
||||
import { LocaleLink } from '@/i18n/navigation';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import * as React from 'react';
|
||||
import { Logo } from '../logo';
|
||||
import { SidebarUpgradeCard } from './sidebar-upgrade-card';
|
||||
import { authClient } from '@/lib/auth-client';
|
||||
|
||||
export function DashboardSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
const t = useTranslations();
|
||||
const mainLinks = getNavMainLinks();
|
||||
const sidebarLinks = getSidebarLinks();
|
||||
const currentUser = useCurrentUser();
|
||||
|
||||
const { data: session, error } = authClient.useSession();
|
||||
const user = session?.user;
|
||||
// user is a member if they have a lifetime membership or an active subscription
|
||||
const isMember = currentUser?.lifetimeMember ||
|
||||
(currentUser?.subscriptionId && currentUser?.subscriptionStatus === 'active');
|
||||
|
||||
return (
|
||||
<Sidebar collapsible="icon" {...props}>
|
||||
@ -47,14 +49,15 @@ export function DashboardSidebar({ ...props }: React.ComponentProps<typeof Sideb
|
||||
</SidebarHeader>
|
||||
|
||||
<SidebarContent>
|
||||
<NavMain items={mainLinks} />
|
||||
<NavMain items={sidebarLinks} />
|
||||
</SidebarContent>
|
||||
|
||||
<SidebarFooter className="flex flex-col gap-4">
|
||||
{/* TODO: show or hide based on user status */}
|
||||
<SidebarUpgradeCard />
|
||||
{/* show upgrade card if user is not a member */}
|
||||
{!isMember && <SidebarUpgradeCard />}
|
||||
|
||||
{user && <NavUser user={user} />}
|
||||
{/* show user profile if user is logged in */}
|
||||
{currentUser && <NavUser user={currentUser} />}
|
||||
</SidebarFooter>
|
||||
</Sidebar>
|
||||
);
|
||||
|
@ -20,7 +20,7 @@ import { useEffect, useTransition } from 'react';
|
||||
*
|
||||
* Allows users to switch between available locales using a dropdown menu.
|
||||
*
|
||||
* Based on next-intl's useLocaleRouter and usePathname for locale navigation.
|
||||
* Based on next-intl's useLocaleRouter and useLocalePathname for locale navigation.
|
||||
* https://next-intl.dev/docs/routing/navigation#userouter
|
||||
*/
|
||||
export default function LocaleSwitcher() {
|
||||
|
@ -93,12 +93,15 @@ export function PricingCard({
|
||||
className
|
||||
)}
|
||||
>
|
||||
{/* show popular badge if plan is recommended */}
|
||||
{plan.recommended && (
|
||||
<span className="absolute inset-x-0 -top-3 mx-auto flex h-6 w-fit items-center rounded-full px-3 py-1 text-xs font-medium border
|
||||
bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200 border-purple-200 dark:border-purple-800 shadow-sm">
|
||||
{t('popular')}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* show current plan badge if plan is current plan */}
|
||||
{isCurrentPlan && (
|
||||
<span className="absolute inset-x-0 -top-3 mx-auto flex h-6 w-fit items-center rounded-full px-3 py-1 text-xs font-medium border
|
||||
bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-100 border-blue-200 dark:border-blue-800 shadow-sm">
|
||||
@ -109,6 +112,7 @@ export function PricingCard({
|
||||
<CardHeader>
|
||||
<CardTitle className="font-medium">{plan.name}</CardTitle>
|
||||
|
||||
{/* show price and price label */}
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="my-4 block text-4xl font-semibold">
|
||||
{formattedPrice}
|
||||
@ -118,6 +122,7 @@ export function PricingCard({
|
||||
|
||||
<CardDescription className="text-sm">{plan.description}</CardDescription>
|
||||
|
||||
{/* show action buttons based on plans */}
|
||||
{plan.isFree ? (
|
||||
currentUser ? (
|
||||
<Button variant="outline" className="mt-4 w-full disabled">
|
||||
@ -162,6 +167,7 @@ export function PricingCard({
|
||||
<CardContent className="space-y-4">
|
||||
<hr className="border-dashed" />
|
||||
|
||||
{/* show trial period if it exists */}
|
||||
{hasTrialPeriod && (
|
||||
<div className="my-4">
|
||||
<span className="inline-block px-2.5 py-1.5 text-xs font-medium rounded-md
|
||||
@ -171,6 +177,7 @@ export function PricingCard({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* show features of this plan */}
|
||||
<ul className="list-outside space-y-4 text-sm">
|
||||
{plan.features.map((feature, i) => (
|
||||
<li key={i} className="flex items-center gap-2">
|
||||
|
@ -1,10 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useLocaleRouter } from '@/i18n/navigation';
|
||||
import { LocaleLink, useLocaleRouter } from '@/i18n/navigation';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { ArrowLeftIcon } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
|
||||
interface BackButtonSmallProps {
|
||||
href?: string;
|
||||
@ -29,9 +28,9 @@ export default function BackButtonSmall({
|
||||
asChild
|
||||
>
|
||||
{/* if href is provided, use it, otherwise use the router.back() */}
|
||||
<Link href={href || '#'} onClick={handleBack}>
|
||||
<LocaleLink href={href || '#'} onClick={handleBack}>
|
||||
<ArrowLeftIcon className="size-4" />
|
||||
</Link>
|
||||
</LocaleLink>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
@ -425,14 +425,14 @@ export function getAvatarLinks(): MenuItem[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sidebar navigation main links with translations
|
||||
* Get sidebar navigation links with translations
|
||||
*
|
||||
* NOTICE: used in client components only
|
||||
*
|
||||
* @param t - The translation function
|
||||
* @returns The menu links with translated titles and descriptions
|
||||
*/
|
||||
export function getNavMainLinks(): NestedMenuItem[] {
|
||||
export function getSidebarLinks(): NestedMenuItem[] {
|
||||
const t = useTranslations();
|
||||
|
||||
return [
|
||||
|
@ -14,9 +14,9 @@ export const user = pgTable("user", {
|
||||
banReason: text('ban_reason'),
|
||||
banExpires: timestamp('ban_expires'),
|
||||
customerId: text('customer_id'),
|
||||
lifetimeMember: boolean('lifetime_member'),
|
||||
subscriptionId: text('subscription_id'),
|
||||
subscriptionStatus: text('subscription_status'),
|
||||
lifetimeMember: boolean('lifetime_member')
|
||||
});
|
||||
|
||||
export const session = pgTable("session", {
|
||||
|
@ -116,17 +116,23 @@ export const auth = betterAuth({
|
||||
defaultValue: "",
|
||||
input: false, // don't allow user to set customerId
|
||||
},
|
||||
lifetimeMember: {
|
||||
type: "boolean",
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
input: false, // don't allow user to set lifetimeMember
|
||||
},
|
||||
subscriptionId: {
|
||||
type: "string",
|
||||
required: false,
|
||||
defaultValue: "",
|
||||
input: false, // don't allow user to set subscriptionId
|
||||
},
|
||||
lifetimeMember: {
|
||||
type: "boolean",
|
||||
subscriptionStatus: {
|
||||
type: "string",
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
input: false, // don't allow user to set lifetimeMember
|
||||
defaultValue: "",
|
||||
input: false, // don't allow user to set subscriptionStatus
|
||||
},
|
||||
},
|
||||
// https://www.better-auth.com/docs/concepts/users-accounts#delete-user
|
||||
|
Loading…
Reference in New Issue
Block a user