diff --git a/app/(business)/business/layout.tsx b/app/(business)/business/layout.tsx index ef513859..ebcc33fa 100644 --- a/app/(business)/business/layout.tsx +++ b/app/(business)/business/layout.tsx @@ -7,7 +7,7 @@ import { AppProviders } from 'app/providers' import { pretendard } from 'app/styles' import { GoogleAnalytics } from 'shared/config/google-analytics' import { cn } from 'shared/lib' -import { BusinessGNB } from 'shared/ui' +import { BusinessGNB } from 'widgets/gnb' import '../../globals.css' diff --git a/app/(guest)/layout.tsx b/app/(guest)/layout.tsx index d556a66f..eaf25cdb 100644 --- a/app/(guest)/layout.tsx +++ b/app/(guest)/layout.tsx @@ -6,7 +6,7 @@ import { ReactNode } from 'react' import { pretendard } from 'app/styles' import { GoogleAnalytics } from 'shared/config/google-analytics' import { cn } from 'shared/lib' -import { GuestGNB } from 'shared/ui' +import { GuestGNB } from 'widgets/gnb' import '../globals.css' diff --git a/app/(user)/layout.tsx b/app/(user)/layout.tsx index 8ea0977c..16513646 100644 --- a/app/(user)/layout.tsx +++ b/app/(user)/layout.tsx @@ -7,7 +7,7 @@ import { AppProviders } from 'app/providers' import { pretendard } from 'app/styles' import { GoogleAnalytics } from 'shared/config/google-analytics' import { cn } from 'shared/lib' -import { GNB } from 'shared/ui' +import { GNB } from 'widgets/gnb' import '../globals.css' diff --git a/src/shared/ui/gnb/assets/Logo.svg b/public/images/logo.svg similarity index 100% rename from src/shared/ui/gnb/assets/Logo.svg rename to public/images/logo.svg diff --git a/src/entities/notification/api/get-notification-unread-count.ts b/src/entities/notification/api/get-notification-unread-count.ts new file mode 100644 index 00000000..207f5162 --- /dev/null +++ b/src/entities/notification/api/get-notification-unread-count.ts @@ -0,0 +1,34 @@ +'use server' + +import { getTeacherSession, getBusinessSession } from 'entities/auth' +import { apiClient } from 'shared/api' + +import { NotificationUnreadCount } from '../model/setting' + +type GetNotificationUnreadCountResponse = NotificationUnreadCount + +export const getTeacherNotificationUnreadCount = async () => { + const { accessToken } = await getTeacherSession() + + const response = await apiClient.get({ + endpoint: `/notifications/unread-count`, + option: { + authorization: `Bearer ${accessToken}`, + }, + }) + + return response +} + +export const getBusinessNotificationUnreadCount = async () => { + const { accessToken } = await getBusinessSession() + + const response = await apiClient.get({ + endpoint: `/notifications/unread-count`, + option: { + authorization: `Bearer ${accessToken}`, + }, + }) + + return response +} diff --git a/src/entities/notification/api/get-notifications.ts b/src/entities/notification/api/get-notifications.ts new file mode 100644 index 00000000..c3b6cefa --- /dev/null +++ b/src/entities/notification/api/get-notifications.ts @@ -0,0 +1,42 @@ +'use server' + +import { getBusinessSession, getTeacherSession } from 'entities/auth' +import { apiClient, Pagination, PaginationParams } from 'shared/api' + +import { Notification } from '../model/notification' + +export type GetNotificationsRequest = PaginationParams + +type GetNotificationsResponse = Pagination + +export const getTeacherNotifications = async ( + queryParams: GetNotificationsRequest, +) => { + const { accessToken } = await getTeacherSession() + + const response = await apiClient.get({ + endpoint: '/notifications', + queryParams, + option: { + authorization: `Bearer ${accessToken}`, + }, + }) + + return response +} + +export const getBusinessNotifications = async ( + queryParams: GetNotificationsRequest, +) => { + const { accessToken } = await getBusinessSession() + + const response = await apiClient.get({ + endpoint: '/notifications', + queryParams, + option: { + authorization: `Bearer ${accessToken}`, + }, + }) + + return response +} diff --git a/src/entities/notification/api/query.ts b/src/entities/notification/api/query.ts new file mode 100644 index 00000000..182ccaec --- /dev/null +++ b/src/entities/notification/api/query.ts @@ -0,0 +1,49 @@ +import { infiniteQueryOptions, queryOptions } from '@tanstack/react-query' + +import { + getBusinessNotificationUnreadCount, + getTeacherNotificationUnreadCount, +} from './get-notification-unread-count' +import { + getBusinessNotifications, + getTeacherNotifications, +} from './get-notifications' + +export const notificationQueries = { + all: () => ['notification'], + lists: () => [...notificationQueries.all(), 'list'], + teacherList: () => + infiniteQueryOptions({ + queryKey: [...notificationQueries.lists(), 'teacher'], + queryFn: ({ pageParam = 0 }) => + getTeacherNotifications({ pageNumber: pageParam, rowCount: 10 }), + initialPageParam: 0, + getNextPageParam: lastPage => { + if (lastPage.last) return undefined + + return lastPage.pageable.pageNumber + 1 + }, + }), + businessList: () => + infiniteQueryOptions({ + queryKey: [...notificationQueries.lists(), 'business'], + queryFn: ({ pageParam = 0 }) => + getBusinessNotifications({ pageNumber: pageParam, rowCount: 10 }), + initialPageParam: 0, + getNextPageParam: lastPage => { + if (lastPage.last) return undefined + + return lastPage.pageable.pageNumber + 1 + }, + }), + teacherUnreadCount: () => + queryOptions({ + queryKey: [...notificationQueries.lists(), 'teacher', 'unread-count'], + queryFn: getTeacherNotificationUnreadCount, + }), + businessUnreadCount: () => + queryOptions({ + queryKey: [...notificationQueries.lists(), 'business', 'unread-count'], + queryFn: getBusinessNotificationUnreadCount, + }), +} diff --git a/src/entities/notification/index.ts b/src/entities/notification/index.ts index 63acf59d..4dca1f8d 100644 --- a/src/entities/notification/index.ts +++ b/src/entities/notification/index.ts @@ -6,4 +6,5 @@ export { updateTeacherNotificationSetting, updateBusinessNotificationSetting, } from './api/update-notification-setting' +export { notificationQueries } from './api/query' export type { NotificationSetting } from './model/setting' diff --git a/src/entities/notification/model/notification.ts b/src/entities/notification/model/notification.ts new file mode 100644 index 00000000..eb44823b --- /dev/null +++ b/src/entities/notification/model/notification.ts @@ -0,0 +1,9 @@ +export type Notification = { + id: number + title: string + titleEn: string + content: string + contentEn: string + targetUrl: string + createdAt: string +} diff --git a/src/entities/notification/model/setting.ts b/src/entities/notification/model/setting.ts index 4f9027a5..399ee02e 100644 --- a/src/entities/notification/model/setting.ts +++ b/src/entities/notification/model/setting.ts @@ -1,3 +1,8 @@ export type NotificationSetting = { allowEmail: boolean } + +export type NotificationUnreadCount = { + hasUnreadNotification: boolean + count: number +} diff --git a/src/shared/ui/gnb/index.ts b/src/shared/ui/gnb/index.ts deleted file mode 100644 index 9b629bbc..00000000 --- a/src/shared/ui/gnb/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { GNB } from './gnb' -export { BusinessGNB } from './business-gnb' -export { GuestGNB } from './guest-gnb' diff --git a/src/shared/ui/index.ts b/src/shared/ui/index.ts index 275bb7b4..ad1e3dfa 100644 --- a/src/shared/ui/index.ts +++ b/src/shared/ui/index.ts @@ -7,7 +7,6 @@ export { DatePicker } from './date-picker' export { Dropdown } from './dropdown' export { ErrorPage } from './error/error-page' export { Filter, type FilterValue } from './filter' -export { GNB, BusinessGNB, GuestGNB } from './gnb' export { Heading } from './heading' export { HelperText, type HelperTextProps } from './helper-text' export { Icon } from './icon' diff --git a/src/shared/ui/layout/layout.tsx b/src/shared/ui/layout/layout.tsx index 3f0c560a..8d9873d7 100644 --- a/src/shared/ui/layout/layout.tsx +++ b/src/shared/ui/layout/layout.tsx @@ -15,9 +15,11 @@ export const Layout = ({ children, }: PropsWithChildren) => { return ( -
-
- {children} +
+
+
+ {children} +
) diff --git a/src/shared/ui/layout/variants.ts b/src/shared/ui/layout/variants.ts index a2e31045..c877c20e 100644 --- a/src/shared/ui/layout/variants.ts +++ b/src/shared/ui/layout/variants.ts @@ -1,6 +1,6 @@ import { cva, VariantProps } from 'class-variance-authority' -export const outerWrapper = cva('h-fit w-fit flex-grow', { +export const outerWrapper = cva('h-[calc(100dvh-65px)] w-fit flex-grow', { variants: { wide: { true: 'mx-auto my-0 flex', diff --git a/src/shared/ui/modal/modal.tsx b/src/shared/ui/modal/modal.tsx index a1cd23f3..714900fe 100644 --- a/src/shared/ui/modal/modal.tsx +++ b/src/shared/ui/modal/modal.tsx @@ -51,7 +51,7 @@ const ModalOverlay = forwardRef< { + const { data, refetch } = useQuery(notificationQueries.businessUnreadCount()) + + return { + hasUnreadNotification: data?.hasUnreadNotification, + refetch, + } +} diff --git a/src/widgets/gnb/api/get-business-notifications.ts b/src/widgets/gnb/api/get-business-notifications.ts new file mode 100644 index 00000000..5320e306 --- /dev/null +++ b/src/widgets/gnb/api/get-business-notifications.ts @@ -0,0 +1,15 @@ +import { useInfiniteQuery } from '@tanstack/react-query' + +import { notificationQueries } from 'entities/notification' +import { useEmptyBoundary } from 'shared/api' + +export const useBusinessNotifications = () => { + const result = useInfiniteQuery({ + ...notificationQueries.businessList(), + select: data => data?.pages.flatMap(page => page.content), + }) + + useEmptyBoundary(result.data) + + return result +} diff --git a/src/widgets/gnb/api/get-teacher-notification-unread-count.ts b/src/widgets/gnb/api/get-teacher-notification-unread-count.ts new file mode 100644 index 00000000..8d7b82a0 --- /dev/null +++ b/src/widgets/gnb/api/get-teacher-notification-unread-count.ts @@ -0,0 +1,12 @@ +import { useQuery } from '@tanstack/react-query' + +import { notificationQueries } from 'entities/notification' + +export const useTeacherNotificationUnreadCount = () => { + const { data, refetch } = useQuery(notificationQueries.teacherUnreadCount()) + + return { + hasUnreadNotification: data?.hasUnreadNotification, + refetch, + } +} diff --git a/src/widgets/gnb/api/get-teacher-notifications.ts b/src/widgets/gnb/api/get-teacher-notifications.ts new file mode 100644 index 00000000..3cddf9ac --- /dev/null +++ b/src/widgets/gnb/api/get-teacher-notifications.ts @@ -0,0 +1,15 @@ +import { useInfiniteQuery } from '@tanstack/react-query' + +import { notificationQueries } from 'entities/notification' +import { useEmptyBoundary } from 'shared/api' + +export const useTeacherNotifications = () => { + const result = useInfiniteQuery({ + ...notificationQueries.teacherList(), + select: data => data?.pages.flatMap(page => page.content), + }) + + useEmptyBoundary(result.data) + + return result +} diff --git a/src/widgets/gnb/index.ts b/src/widgets/gnb/index.ts new file mode 100644 index 00000000..cf48e3c0 --- /dev/null +++ b/src/widgets/gnb/index.ts @@ -0,0 +1,3 @@ +export { GNB } from './ui/gnb' +export { BusinessGNB } from './ui/business-gnb' +export { GuestGNB } from './ui/guest-gnb' diff --git a/src/widgets/gnb/lib/format-date.ts b/src/widgets/gnb/lib/format-date.ts new file mode 100644 index 00000000..143be5a0 --- /dev/null +++ b/src/widgets/gnb/lib/format-date.ts @@ -0,0 +1,28 @@ +import { format, differenceInMinutes, differenceInHours } from 'date-fns' +import { enUS, ko } from 'date-fns/locale' + +export const formatNotificationDate = ( + createdAt: string | Date, + locale: 'ko' | 'en' = 'ko', +): string => { + const now = new Date() + const created = + typeof createdAt === 'string' ? new Date(createdAt) : createdAt + + const diffMinutes = differenceInMinutes(now, created) + const diffHours = differenceInHours(now, created) + + if (diffMinutes < 1) { + return locale === 'ko' ? '1분 전' : '1minute ago' + } + if (diffMinutes < 60) { + return locale === 'ko' ? `${diffMinutes}분 전` : `${diffMinutes}minutes ago` + } + if (diffHours < 24) { + return locale === 'ko' ? `${diffHours}시간 전` : `${diffHours}hours ago` + } + + return format(created, 'yyyy.MM.dd(eee)', { + locale: locale === 'ko' ? ko : enUS, + }) +} diff --git a/src/shared/ui/gnb/business-button.tsx b/src/widgets/gnb/ui/business-button.tsx similarity index 97% rename from src/shared/ui/gnb/business-button.tsx rename to src/widgets/gnb/ui/business-button.tsx index 04498352..37518a9d 100644 --- a/src/shared/ui/gnb/business-button.tsx +++ b/src/widgets/gnb/ui/business-button.tsx @@ -8,9 +8,7 @@ import { businessSignOut } from 'entities/auth' import { colors, type Locale } from 'shared/config' import { useDropdown } from 'shared/lib' import { setLocale } from 'shared/server-lib' - -import { Dropdown } from '../dropdown' -import { Icon } from '../icon' +import { Dropdown, Icon } from 'shared/ui' export const BusinessButton = () => { const router = useRouter() diff --git a/src/shared/ui/gnb/business-gnb.tsx b/src/widgets/gnb/ui/business-gnb.tsx similarity index 93% rename from src/shared/ui/gnb/business-gnb.tsx rename to src/widgets/gnb/ui/business-gnb.tsx index a795bfee..975d0036 100644 --- a/src/shared/ui/gnb/business-gnb.tsx +++ b/src/widgets/gnb/ui/business-gnb.tsx @@ -4,13 +4,13 @@ import { useRouter } from 'next/navigation' import { useSession } from 'next-auth/react' import { useTranslations } from 'next-intl' +import Logo from 'public/images/logo.svg' import { cn } from 'shared/lib' +import { Button } from 'shared/ui' -import { Button } from '../button' -import Logo from './assets/Logo.svg' import { BusinessButton } from './business-button' +import { NotificationButton } from './business-notification/button' import * as Navigation from './navigation' -import { NotificationButton } from './notification' import * as css from './variants' export const BusinessGNB = () => { @@ -19,8 +19,6 @@ export const BusinessGNB = () => { const t = useTranslations() - const isDev = process.env.NODE_ENV === 'development' - const handleLogoClick = () => { router.push('/business') } diff --git a/src/widgets/gnb/ui/business-notification/button.tsx b/src/widgets/gnb/ui/business-notification/button.tsx new file mode 100644 index 00000000..74d0f3d8 --- /dev/null +++ b/src/widgets/gnb/ui/business-notification/button.tsx @@ -0,0 +1,65 @@ +import { useQueryClient } from '@tanstack/react-query' +import { usePathname } from 'next/navigation' +import { useEffect } from 'react' + +import { notificationQueries } from 'entities/notification' +import { EmptyBoundary } from 'shared/api' +import { colors } from 'shared/config' +import { useDropdown } from 'shared/lib' +import { Dropdown, Icon } from 'shared/ui' + +import { BusinessNotificationList, NoNotification } from './list' +import { useBusinessNotificationUnreadCount } from '../../api/get-business-notification-unread-count' + +export const NotificationButton = () => { + const pathname = usePathname() + + const queryClient = useQueryClient() + + const { isOpen, toggleIsOpen, close, dropdownRef } = useDropdown() + + const { hasUnreadNotification, refetch } = + useBusinessNotificationUnreadCount() + + const handleClick = () => { + toggleIsOpen() + } + + useEffect(() => { + if (!isOpen) { + void queryClient.resetQueries({ + queryKey: notificationQueries.businessList().queryKey, + }) + } + }, [isOpen, queryClient]) + + useEffect(() => { + void refetch() + }, [pathname, refetch]) + + return ( +
+ + {isOpen && ( + + }> + + + + )} +
+ ) +} diff --git a/src/widgets/gnb/ui/business-notification/list.tsx b/src/widgets/gnb/ui/business-notification/list.tsx new file mode 100644 index 00000000..fcc090b9 --- /dev/null +++ b/src/widgets/gnb/ui/business-notification/list.tsx @@ -0,0 +1,115 @@ +import { useRouter } from 'next/navigation' +import { useEffect } from 'react' + +import { cn } from 'shared/lib' +import { Dropdown } from 'shared/ui' + +import { useBusinessNotifications } from '../../api/get-business-notifications' +import { formatNotificationDate } from '../../lib/format-date' + +type Props = { + close: () => void + updateCount: () => void +} + +export const BusinessNotificationList = ({ close, updateCount }: Props) => { + const router = useRouter() + + const { data, isLoading, hasNextPage, fetchNextPage } = + useBusinessNotifications() + + useEffect(() => { + if (!isLoading) { + void updateCount() + } + }, [isLoading, updateCount]) + + if (isLoading) { + return + } + + const isLastItem = (index: number) => { + if (!data) return false + + return index === data.length - 1 + } + + return ( + <> + {data?.map((notification, index) => ( + { + if (notification.targetUrl) { + router.push(notification.targetUrl) + close() + } + }} + > +
+
+

+ {notification.title} +

+

+ {notification.content} +

+
+

+ {formatNotificationDate(notification.createdAt, 'ko')} +

+
+
+ ))} + {(() => { + if (hasNextPage) { + return ( + + + + ) + } + + return ( + +

+ 최근 90일간 받은 알림을 모두 표시했어요 +

+
+ ) + })()} + + ) +} + +export const NoNotification = () => { + return ( + +

+ 아직 새로운 알림이 없어요 +

+
+ ) +} + +export const NotificationSkeleton = () => { + return ( + +
+
+
+
+
+
+
+ + ) +} diff --git a/src/shared/ui/gnb/gnb.tsx b/src/widgets/gnb/ui/gnb.tsx similarity index 92% rename from src/shared/ui/gnb/gnb.tsx rename to src/widgets/gnb/ui/gnb.tsx index bb55b92e..edacc298 100644 --- a/src/shared/ui/gnb/gnb.tsx +++ b/src/widgets/gnb/ui/gnb.tsx @@ -4,12 +4,12 @@ import { useRouter } from 'next/navigation' import { useSession } from 'next-auth/react' import { useTranslations } from 'next-intl' +import Logo from 'public/images/logo.svg' import { cn } from 'shared/lib' +import { Button } from 'shared/ui' -import { Button } from '../button' -import Logo from './assets/Logo.svg' import * as Navigation from './navigation' -import { NotificationButton } from './notification' +import { NotificationButton } from './teacher-notification/button' import { UserButton } from './user-button' import * as css from './variants' diff --git a/src/shared/ui/gnb/guest-gnb.tsx b/src/widgets/gnb/ui/guest-gnb.tsx similarity index 93% rename from src/shared/ui/gnb/guest-gnb.tsx rename to src/widgets/gnb/ui/guest-gnb.tsx index 1b8aeb88..f18ef215 100644 --- a/src/shared/ui/gnb/guest-gnb.tsx +++ b/src/widgets/gnb/ui/guest-gnb.tsx @@ -2,9 +2,9 @@ import { useRouter } from 'next/navigation' +import Logo from 'public/images/logo.svg' import { cn } from 'shared/lib' -import Logo from './assets/Logo.svg' import * as css from './variants' export const GuestGNB = () => { diff --git a/src/shared/ui/gnb/navigation.tsx b/src/widgets/gnb/ui/navigation.tsx similarity index 100% rename from src/shared/ui/gnb/navigation.tsx rename to src/widgets/gnb/ui/navigation.tsx diff --git a/src/shared/ui/gnb/notification.tsx b/src/widgets/gnb/ui/notification.tsx similarity index 94% rename from src/shared/ui/gnb/notification.tsx rename to src/widgets/gnb/ui/notification.tsx index cb62f050..0a55f1a3 100644 --- a/src/shared/ui/gnb/notification.tsx +++ b/src/widgets/gnb/ui/notification.tsx @@ -2,9 +2,7 @@ import { useTranslations } from 'next-intl' import { colors } from 'shared/config' import { useDropdown } from 'shared/lib' - -import { Dropdown } from '../dropdown' -import { Icon } from '../icon' +import { Dropdown, Icon } from 'shared/ui' export const NotificationButton = () => { const t = useTranslations() diff --git a/src/widgets/gnb/ui/teacher-notification/button.tsx b/src/widgets/gnb/ui/teacher-notification/button.tsx new file mode 100644 index 00000000..c028af86 --- /dev/null +++ b/src/widgets/gnb/ui/teacher-notification/button.tsx @@ -0,0 +1,64 @@ +import { useQueryClient } from '@tanstack/react-query' +import { usePathname } from 'next/navigation' +import { useEffect } from 'react' + +import { notificationQueries } from 'entities/notification' +import { EmptyBoundary } from 'shared/api' +import { colors } from 'shared/config' +import { useDropdown } from 'shared/lib' +import { Dropdown, Icon } from 'shared/ui' + +import { TeacherNotificationList, NoNotification } from './list' +import { useTeacherNotificationUnreadCount } from '../../api/get-teacher-notification-unread-count' + +export const NotificationButton = () => { + const pathname = usePathname() + + const queryClient = useQueryClient() + + const { isOpen, toggleIsOpen, close, dropdownRef } = useDropdown() + + const { hasUnreadNotification, refetch } = useTeacherNotificationUnreadCount() + + const handleClick = () => { + toggleIsOpen() + } + + useEffect(() => { + if (!isOpen) { + void queryClient.resetQueries({ + queryKey: notificationQueries.teacherList().queryKey, + }) + } + }, [isOpen, queryClient]) + + useEffect(() => { + void refetch() + }, [pathname, refetch]) + + return ( +
+ + {isOpen && ( + + }> + + + + )} +
+ ) +} diff --git a/src/widgets/gnb/ui/teacher-notification/list.tsx b/src/widgets/gnb/ui/teacher-notification/list.tsx new file mode 100644 index 00000000..8b6b7109 --- /dev/null +++ b/src/widgets/gnb/ui/teacher-notification/list.tsx @@ -0,0 +1,117 @@ +import { useRouter } from 'next/navigation' +import { useEffect } from 'react' + +import { cn } from 'shared/lib' +import { Dropdown } from 'shared/ui' + +import { useTeacherNotifications } from '../../api/get-teacher-notifications' +import { formatNotificationDate } from '../../lib/format-date' + +type Props = { + close: () => void + updateCount: () => void +} + +export const TeacherNotificationList = ({ close, updateCount }: Props) => { + const router = useRouter() + + const { data, isLoading, hasNextPage, fetchNextPage } = + useTeacherNotifications() + + useEffect(() => { + if (!isLoading) { + void updateCount() + } + }, [isLoading, updateCount]) + + if (isLoading) { + return + } + + const isLastItem = (index: number) => { + if (!data) return false + + return index === data.length - 1 + } + + return ( + <> + {data?.map((notification, index) => ( + { + if (notification.targetUrl) { + router.push(notification.targetUrl) + close() + } + }} + > +
+
+

+ {notification.titleEn} +

+

+ {notification.contentEn} +

+
+

+ {formatNotificationDate(notification.createdAt, 'en')} +

+
+
+ ))} + {(() => { + if (hasNextPage) { + return ( + + + + ) + } + + return ( + +

+ All notifications received +
+ in the past 90 days have been displayed +

+
+ ) + })()} + + ) +} + +export const NoNotification = () => { + return ( + +

+ You have no new notifications yet +

+
+ ) +} + +export const NotificationSkeleton = () => { + return ( + +
+
+
+
+
+
+
+ + ) +} diff --git a/src/shared/ui/gnb/user-button.tsx b/src/widgets/gnb/ui/user-button.tsx similarity index 97% rename from src/shared/ui/gnb/user-button.tsx rename to src/widgets/gnb/ui/user-button.tsx index 94bb94ad..bddea469 100644 --- a/src/shared/ui/gnb/user-button.tsx +++ b/src/widgets/gnb/ui/user-button.tsx @@ -8,9 +8,7 @@ import { teacherSignOut } from 'entities/auth' import { colors, type Locale } from 'shared/config' import { useDropdown } from 'shared/lib' import { setLocale } from 'shared/server-lib' - -import { Dropdown } from '../dropdown' -import { Icon } from '../icon' +import { Dropdown, Icon } from 'shared/ui' export const UserButton = () => { const router = useRouter() diff --git a/src/shared/ui/gnb/variants.ts b/src/widgets/gnb/ui/variants.ts similarity index 84% rename from src/shared/ui/gnb/variants.ts rename to src/widgets/gnb/ui/variants.ts index 95a40019..6c040e2f 100644 --- a/src/shared/ui/gnb/variants.ts +++ b/src/widgets/gnb/ui/variants.ts @@ -1,7 +1,7 @@ import { cva } from 'class-variance-authority' export const header = cva( - 'sticky top-0 z-sticky w-fit min-w-full border-b border-b-gray-300 bg-white py-3', + 'w-fit min-w-full border-b border-b-gray-300 bg-white py-3', ) export const outerWrapper = cva('mx-auto flex w-fit')