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
17 changes: 17 additions & 0 deletions src/app/(dashboard)/configuracoes/fontes/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Metadata } from 'next'

import { SettingsContainer } from '@/modules/settings/layout/settings-container'

import { FontSizeCards } from '../../../../modules/settings/cards/fontsize/fontsize-cards'

export const metadata: Metadata = {
title: 'Tamanho da fonte',
}

export default function Page() {
return (
<SettingsContainer className='flex flex-col gap-6'>
<FontSizeCards />
</SettingsContainer>
)
}
14 changes: 14 additions & 0 deletions src/app/(dashboard)/configuracoes/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { SettingsSidebar } from '@/modules/settings/layout'

import { SettingsContent } from '../../../modules/settings/layout/settings-content'

export default async function Layout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<div className='flex min-h-svh'>
<SettingsSidebar />
<SettingsContent>{children}</SettingsContent>
</div>
)
}
11 changes: 6 additions & 5 deletions src/app/(dashboard)/configuracoes/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import type { Metadata } from 'next'

import { NotificationPreferences } from '@/modules/settings/cards/notifications/notifications-cards'
import { SettingsContainer } from '@/modules/settings/layout/settings-container'

export const metadata: Metadata = {
title: 'Configurações',
}

import { DashboardContainer } from '@/components/dashboard/container'

export default function Page() {
return (
<DashboardContainer className='flex flex-col gap-6'>
Configurações
</DashboardContainer>
<SettingsContainer>
<NotificationPreferences />
</SettingsContainer>
)
}
13 changes: 13 additions & 0 deletions src/components/ui/switch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use client'
import { Switch as BaseSwitch } from '@base-ui-components/react/switch'

export function Switch() {
return (
<BaseSwitch.Root
defaultChecked
className='data-[checked]:active:bg-primary from-primary active:bg-primary relative mx-3 flex h-5 w-10 cursor-pointer rounded-full bg-gradient-to-r from-35% to-gray-200 to-65% bg-[length:6.5rem_100%] bg-[100%_0%] bg-no-repeat p-px shadow-[inset_0_1.5px_2px] shadow-gray-200 transition-[background-position,box-shadow] duration-[125ms] ease-[cubic-bezier(0.26,0.75,0.38,0.45)] before:absolute before:rounded-full before:outline-offset-2 focus-visible:before:inset-0 focus-visible:before:outline focus-visible:before:outline-2 data-[checked]:bg-[0%_0%]'
>
<BaseSwitch.Thumb className='aspect-square h-full rounded-full bg-white shadow-[0_0_1px_1px,0_1px_1px,1px_2px_4px_-1px] shadow-gray-100 transition-transform duration-150 data-[checked]:translate-x-5 dark:shadow-black/25' />
</BaseSwitch.Root>
)
}
1 change: 1 addition & 0 deletions src/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const ROUTES = {
},
settings: {
main: '/configuracoes',
fontSize: '/configuracoes/fontes',
},
support: {
main: '/suporte',
Expand Down
33 changes: 33 additions & 0 deletions src/modules/settings/cards/fontsize/fontsize-cards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use client'

import { useState } from 'react'

import { FontSizeCard } from '@/modules/settings/cards/fontsize'

type FontSize = 'small' | 'medium' | 'large'

export function FontSizeCards() {
const [selectedSize, setSelectedSize] = useState<FontSize>('medium')

return (
<div className='flex gap-4'>
<FontSizeCard
sizeLabel='Pequeno'
isSelected={selectedSize === 'small'}
onClick={() => setSelectedSize('small')}
/>
<FontSizeCard
sizeLabel='Médio'
textDisplayClass='text-xl'
isSelected={selectedSize === 'medium'}
onClick={() => setSelectedSize('medium')}
/>
<FontSizeCard
sizeLabel='Grande'
textDisplayClass='text-2xl'
isSelected={selectedSize === 'large'}
onClick={() => setSelectedSize('large')}
/>
</div>
)
}
58 changes: 58 additions & 0 deletions src/modules/settings/cards/fontsize/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use client'
import { twMerge } from 'tailwind-merge'

import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'

interface FontSizeCardProps {
sizeLabel: string
textDisplayClass?: string
isSelected?: boolean
onClick?: () => void
className?: string
}

export function FontSizeCard({
sizeLabel,
textDisplayClass,
isSelected = false,
onClick,
className,
}: FontSizeCardProps) {
return (
<Button
variant='ghost'
asChild
className={twMerge(
'focus-visible:ring-offset-background group ring-offset-background focus-visible:ring-ring relative w-fit rounded-lg focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none',
isSelected && 'ring-primary ring-2 ring-offset-2',
)}
onClick={onClick}
>
<Card
className={twMerge(
'flex size-36 flex-col items-center justify-center gap-1 px-3 py-4 transition-colors',
isSelected && 'border-primary',
className,
)}
>
<p
className={twMerge(
'text-foreground-soft font-semibold',
textDisplayClass,
)}
>
Tt
</p>
<span
className={twMerge(
'text-foreground-soft font-normal',
textDisplayClass,
)}
>
{sizeLabel}
</span>
</Card>
</Button>
)
}
15 changes: 15 additions & 0 deletions src/modules/settings/cards/notifications/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Card } from '@/components/ui/card'
import { Switch } from '@/components/ui/switch'

interface NotificationCardProps {
label: string
}

export function NotificationCard({ label }: NotificationCardProps) {
return (
<Card className='flex w-full max-w-4xl items-center p-3'>
<p className='text-foreground-soft mr-auto font-normal'>{label}</p>
<Switch />
</Card>
)
}
12 changes: 12 additions & 0 deletions src/modules/settings/cards/notifications/notifications-cards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { NotificationCard } from './index'

export function NotificationPreferences() {
return (
<div className='flex flex-col gap-3'>
<NotificationCard label='Desejo receber os alertas de notificação no Sistema Viver Melhor referente às minhas atividades.' />
<NotificationCard label='Desejo receber os alertas de novidades no Sistema Viver Melhor.' />
<NotificationCard label='Desejo receber os alertas de instabilidade no Sistema Viver Melhor.' />
<NotificationCard label='Desejo receber alertas de pesquisas de satisfação da Ipê Code no Sistema Viver Melhor' />
</div>
)
}
32 changes: 32 additions & 0 deletions src/modules/settings/layout/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ALargeSmall, BellDot } from 'lucide-react'

import { ROUTES } from '@/constants/routes'

import { SettingsMenuSection } from './settings-menu-section'
import { SettingsSidebarContainer } from './settings-sidebar-container'

export function SettingsSidebar() {
return (
<SettingsSidebarContainer>
<SettingsMenuSection sections={SETTINGS_SIDEBAR_SECTIONS} />
</SettingsSidebarContainer>
)
}

const SETTINGS_SIDEBAR_SECTIONS = [
{
id: 'common',
links: [
{
label: 'Notificações',
icon: <BellDot />,
path: ROUTES.dashboard.settings.main,
},
{
label: 'Tamanho da fonte',
icon: <ALargeSmall />,
path: ROUTES.dashboard.settings.fontSize,
},
],
},
]
8 changes: 8 additions & 0 deletions src/modules/settings/layout/settings-container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { cn } from '@/utils/class-name-merge'

export function SettingsContainer({
className,
...props
}: Readonly<React.ComponentProps<'main'>>) {
return <main className={cn('flex-1 p-8', className)} {...props} />
}
39 changes: 39 additions & 0 deletions src/modules/settings/layout/settings-content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use client'

import { usePathname } from 'next/navigation'
import { type ReactNode } from 'react'

import { SettingsHeader } from '@/modules/settings/layout/settings-header'

const HEADERS_TEXT = {
notificacoes: {
title: 'Notificações',
description: 'Gerencie quais notificações deseja receber.',
},
fontes: {
title: 'Tamanho da fonte',
description: 'Selecione o tamanho da fonte',
},
policies: {
title: 'Políticas de privacidade e termos de uso',
description: 'Revise nossas políticas de privacidade e termos de uso.',
},
}

export function SettingsContent({ children }: { children: ReactNode }) {
const pathname = usePathname()
const pathSegments = pathname.split('/')
const lastSegment = pathSegments[pathSegments.length - 1]

const pageKey = lastSegment === 'configuracoes' ? 'notificacoes' : lastSegment

const { title, description } =
HEADERS_TEXT[pageKey as keyof typeof HEADERS_TEXT]

return (
<div className='flex flex-1 flex-col overflow-hidden'>
<SettingsHeader title={title} description={description} />
{children}
</div>
)
}
18 changes: 18 additions & 0 deletions src/modules/settings/layout/settings-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Divider } from '@/components/ui/divider'

interface SettingsHeaderProps {
title: string
description: string
}

export function SettingsHeader({ title, description }: SettingsHeaderProps) {
return (
<>
<header className='flex flex-col gap-1 px-8 py-4'>
<h1 className='text-xl font-medium'>{title}</h1>
<p className='text-foreground-soft'>{description}</p>
</header>
<Divider />
</>
)
}
51 changes: 51 additions & 0 deletions src/modules/settings/layout/settings-menu-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use client'
import { usePathname } from 'next/navigation'

import { NavButton } from '@/components/ui/nav-button'
import { cn } from '@/utils/class-name-merge'

interface SettingsMenuSectionProps {
sections: {
id: string
links: {
label: string
icon: React.ReactNode
path: string
}[]
}[]
}

export function SettingsMenuSection({
sections,
}: Readonly<SettingsMenuSectionProps>) {
const pathname = usePathname()

return (
<section className='mb-auto space-y-8'>
{sections.map((section) => (
<section key={section.id}>
<nav className='flex flex-col gap-2'>
{section.links.map((link) => {
const isActive = link.path === pathname

return (
<NavButton
key={link.label}
variant='ghost'
href={link.path}
data-active={isActive}
className={cn(
'[&_svg]:text-disabled text-foreground-soft data-[active=true]:text-primary-foreground data-[active=true]:[&_svg]:text-primary-foreground data-[active=true]:bg-primary min-w-full justify-start gap-3 px-2.5 data-[active=true]:pointer-events-none data-[active=true]:size-10',
)}
>
{link.icon}
{link.label}
</NavButton>
)
})}
</nav>
</section>
))}
</section>
)
}
14 changes: 14 additions & 0 deletions src/modules/settings/layout/settings-sidebar-container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export function SettingsSidebarContainer({
...props
}: Readonly<React.ComponentProps<'aside'>>) {
return (
<div className='relative'>
<aside
className={
'border-border flex h-screen w-60 shrink-0 flex-col gap-8 overflow-x-hidden overflow-y-auto border-r px-6 py-6'
}
{...props}
/>
</div>
)
}