Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions app/collection/items/[slug]/components/carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import NextImage from 'next/image'
import clsx from 'clsx'
import { ImagesEdit } from './edit-fields/images-edit'
import { type BarometerDTO } from '@/app/types'
import { IsAdmin } from '@/app/components/is-admin'
import 'swiper/css'
import 'swiper/css/zoom'
import 'swiper/css/navigation'
Expand All @@ -16,13 +17,14 @@ import './styles.css'
interface ImageCarouselProps {
images: string[]
barometer: BarometerDTO
isAdmin: boolean
}

export function ImageCarousel({ images, barometer, isAdmin }: ImageCarouselProps) {
export function ImageCarousel({ images, barometer }: ImageCarouselProps) {
return (
<Box style={{ overflow: 'hidden', position: 'relative' }}>
{isAdmin && <ImagesEdit barometer={barometer} />}
<IsAdmin>
<ImagesEdit barometer={barometer} />
</IsAdmin>
<Swiper
zoom
loop={images.length > 1}
Expand Down
54 changes: 27 additions & 27 deletions app/collection/items/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { type Metadata } from 'next'
import { getServerSession } from 'next-auth'
import capitalize from 'lodash/capitalize'
import { Container, Title, Text, Box, Divider, Tooltip } from '@mantine/core'
import { AccessRole } from '@prisma/client'
import { authConfig, getUserByEmail } from '@/utils/auth'
import { googleStorageImagesFolder, barometerRoute } from '@/app/constants'
import { ImageCarousel } from './components/carousel'
import { Condition } from './components/condition'
Expand All @@ -19,6 +16,7 @@ import { title, openGraph, twitter } from '@/app/metadata'
import { Dimensions } from '@/app/types'
import { withPrisma } from '@/prisma/prismaClient'
import { getBarometer } from '@/app/api/v2/barometers/[slug]/getters'
import { IsAdmin } from '@/app/components/is-admin'

export const dynamic = 'force-static'

Expand Down Expand Up @@ -71,20 +69,7 @@ export const generateStaticParams = withPrisma(prisma =>
prisma.barometer.findMany({ select: { slug: true } }),
)

async function isAuthorized(): Promise<boolean> {
try {
const session = await getServerSession(authConfig)
const email = session?.user?.email
if (!email) return false
const { role } = await getUserByEmail(email)
return role === AccessRole.ADMIN
} catch (error) {
return false
}
}

export default async function BarometerItem({ params: { slug } }: BarometerItemProps) {
const isAdmin = await isAuthorized()
const barometer = await getBarometer(slug)
const { name, images, description, manufacturer, dateDescription, condition, collectionId } =
barometer
Expand All @@ -94,15 +79,16 @@ export default async function BarometerItem({ params: { slug } }: BarometerItemP
<Box px={{ base: 'none', sm: 'xl' }} pb={{ base: 'xl', sm: '5rem' }}>
<BreadcrumbsComponent catId={barometer.collectionId} type={barometer.category.name} />
<ImageCarousel
isAdmin={isAdmin}
barometer={barometer}
images={images.map(image => googleStorageImagesFolder + image)}
/>
<Box mb="md">
<Title className={sx.title}>{`${name.split(' ').slice(0, -1).join(' ')} `}</Title>
<Title className={sx.title} style={{ whiteSpace: 'nowrap' }}>
{name.split(' ').at(-1)}
{isAdmin && <TextFieldEdit barometer={barometer} property="name" size={22} />}
<IsAdmin>
<TextFieldEdit barometer={barometer} property="name" size={22} />
</IsAdmin>
</Title>
<Tooltip label="Collection ID">
<Text className={sx.collectionId}>{collectionId}</Text>
Expand All @@ -116,7 +102,9 @@ export default async function BarometerItem({ params: { slug } }: BarometerItemP
</Title>
<Text c="dark.3" fw={400} display="inline">
{`${manufacturer.name}${manufacturer.city ? `, ${manufacturer.city}` : ''}`}
{isAdmin && <ManufacturerEdit barometer={barometer} />}
<IsAdmin>
<ManufacturerEdit barometer={barometer} />
</IsAdmin>
</Text>
</Box>
)}
Expand All @@ -127,7 +115,9 @@ export default async function BarometerItem({ params: { slug } }: BarometerItemP
</Title>
<Text c="dark.3" fw={400} display="inline">
{dateDescription}
{isAdmin && <TextFieldEdit barometer={barometer} property="dateDescription" />}
<IsAdmin>
<TextFieldEdit barometer={barometer} property="dateDescription" />
</IsAdmin>
</Text>
</Box>

Expand All @@ -141,28 +131,38 @@ export default async function BarometerItem({ params: { slug } }: BarometerItemP
{index < arr.length - 1 ? ', ' : ''}
</Text>
))}
{isAdmin && <DimensionEdit barometer={barometer} />}
<IsAdmin>
<DimensionEdit barometer={barometer} />
</IsAdmin>
</Title>
</Box>
)}

<Condition
condition={condition}
editButton={isAdmin && <ConditionEdit barometer={barometer} />}
editButton={
<IsAdmin>
<ConditionEdit barometer={barometer} />
</IsAdmin>
}
/>

<Divider
mx="lg"
my="lg"
{...(isAdmin && {
label: <DescriptionEdit barometer={barometer} />,
labelPosition: 'right',
})}
labelPosition="right"
label={
<IsAdmin>
<DescriptionEdit barometer={barometer} />
</IsAdmin>
}
/>
{description ? (
<DescriptionText description={description} />
) : (
isAdmin && <Text>Add description</Text>
<IsAdmin>
<Text>Add description</Text>
</IsAdmin>
)}
</Box>
</Container>
Expand Down
7 changes: 4 additions & 3 deletions app/components/header/menudata.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
type UserType = 'Simple' | 'Admin'
import { AccessRole } from '@prisma/client'

interface MenuItem {
id: number
label: string
link: string
visibleFor?: UserType
visibleFor?: AccessRole
}

export const menuData: MenuItem[] = [
Expand Down Expand Up @@ -36,6 +37,6 @@ export const menuData: MenuItem[] = [
id: 10,
label: 'Admin',
link: 'admin',
visibleFor: 'Admin',
visibleFor: AccessRole.ADMIN,
},
]
8 changes: 5 additions & 3 deletions app/components/header/mobile-menu/mobile-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ import * as motion from 'framer-motion/client'
import { SiMaildotru, SiInstagram } from 'react-icons/si'
import { IoIosArrowForward as Arrow } from 'react-icons/io'
import { useSession } from 'next-auth/react'
import { AccessRole } from '@prisma/client'
import { instagram, email, barometerTypesRoute } from '@/app/constants'
import { menuData } from '../menudata'
import { useBarometers } from '@/app/hooks/useBarometers'
import { isAdmin } from '../../is-admin'

export const MobileMenu: FC<DrawerProps> = props => {
const { status } = useSession()
const isLoggedId = status === 'authenticated'
const { data: session } = useSession()
const [opened, setOpened] = useState<Record<number, boolean>>({})
const toggle = (index: number) => setOpened(old => ({ ...old, [index]: !old[index] }))
const { categories } = useBarometers()
Expand Down Expand Up @@ -57,7 +58,8 @@ export const MobileMenu: FC<DrawerProps> = props => {
{menuData
.filter(
({ visibleFor }) =>
typeof visibleFor === 'undefined' || (isLoggedId && visibleFor === 'Admin'),
typeof visibleFor === 'undefined' ||
(isAdmin(session) && visibleFor === AccessRole.ADMIN),
)
.map((outer, i, arr) => (
<Fragment key={outer.id}>
Expand Down
8 changes: 5 additions & 3 deletions app/components/header/tabs/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ import clsx from 'clsx'
import dynamic from 'next/dynamic'
import Link from 'next/link'
import { useSession } from 'next-auth/react'
import { AccessRole } from '@prisma/client'
import sx from './tabs.module.scss'
import { menuData } from '../menudata'
import { useBarometers } from '@/app/hooks/useBarometers'
import { barometerTypesRoute } from '@/app/constants'
import { isAdmin } from '../../is-admin'

const WideScreenTabs = ({ className, ...props }: CenterProps) => {
const { categories: types } = useBarometers()
const { status } = useSession()
const isLoggedId = status === 'authenticated'
const { data: session } = useSession()
const router = useRouter()
const pathname = usePathname()
const [activeTab, setActiveTab] = useState(-1)
Expand Down Expand Up @@ -45,7 +46,8 @@ const WideScreenTabs = ({ className, ...props }: CenterProps) => {
{menuData
.filter(
({ visibleFor }) =>
typeof visibleFor === 'undefined' || (isLoggedId && visibleFor === 'Admin'),
typeof visibleFor === 'undefined' ||
(isAdmin(session) && visibleFor === AccessRole.ADMIN),
)
.map((menuitem, i) => {
const renderTab = (key?: Key) => (
Expand Down
1 change: 1 addition & 0 deletions app/components/is-admin/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { IsAdmin, isAdmin } from './is-admin'
16 changes: 16 additions & 0 deletions app/components/is-admin/is-admin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use client'

import { type PropsWithChildren } from 'react'
import { useSession } from 'next-auth/react'
import { AccessRole } from '@prisma/client'
import { Session } from 'next-auth'

export function isAdmin(session: Session | null): boolean {
const user = session?.user
return user?.role === AccessRole.ADMIN
}

export function IsAdmin({ children }: PropsWithChildren) {
const { data } = useSession()
return isAdmin(data) ? <>{children}</> : <></>
}
17 changes: 17 additions & 0 deletions env.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { AccessRole } from '@prisma/client'

declare namespace NodeJS {
interface ProcessEnv {
AUTH_SECRET: string
Expand All @@ -9,3 +11,18 @@ declare namespace NodeJS {
GCP_PRIVATE_KEY: string
}
}

declare module 'next-auth' {
interface User {
role?: AccessRole
}
interface Session {
user: User
}
}

declare module 'next-auth/jwt' {
interface JWT {
role?: AccessRole
}
}
17 changes: 17 additions & 0 deletions utils/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const authConfig: AuthOptions = {
email: user.email,
name: user.name,
image: user.avatarURL,
role: user.role,
} as User
},
}),
Expand All @@ -38,4 +39,20 @@ export const authConfig: AuthOptions = {
session: {
strategy: 'jwt',
},
callbacks: {
async jwt({ token, user }) {
// Adding Role to token if it exists in User
if (user?.role) {
token.role = user.role
}
return token
},
async session({ session, token }) {
// Passing role from token to session
if (token.role) {
session.user.role = token.role
}
return session
},
},
}
Loading