feat: refresh Raven branding
This commit is contained in:
parent
6e2bbb3494
commit
c00b4300c1
31 changed files with 128 additions and 138 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 73 KiB |
BIN
src/app/icon.png
BIN
src/app/icon.png
Binary file not shown.
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 567 KiB |
|
|
@ -5,7 +5,6 @@ import Image from "next/image"
|
|||
import Link from "next/link"
|
||||
import { useRouter, useSearchParams } from "next/navigation"
|
||||
import dynamic from "next/dynamic"
|
||||
import { GalleryVerticalEnd } from "lucide-react"
|
||||
|
||||
import { LoginForm } from "@/components/login-form"
|
||||
import { useSession } from "@/lib/auth-client"
|
||||
|
|
@ -57,9 +56,14 @@ export function LoginPageClient() {
|
|||
<div className="flex flex-col gap-6 p-6 md:p-10">
|
||||
<div className="flex flex-col items-center gap-1.5 text-center">
|
||||
<Link href="/" className="flex items-center gap-2 text-xl font-semibold text-neutral-900">
|
||||
<div className="bg-primary text-primary-foreground flex size-6 items-center justify-center rounded-md">
|
||||
<GalleryVerticalEnd className="size-4" />
|
||||
</div>
|
||||
<Image
|
||||
src="/logo-raven.png"
|
||||
alt="Logotipo Raven"
|
||||
width={40}
|
||||
height={40}
|
||||
className="h-10 w-auto"
|
||||
priority
|
||||
/>
|
||||
Raven
|
||||
</Link>
|
||||
</div>
|
||||
|
|
@ -70,11 +74,11 @@ export function LoginPageClient() {
|
|||
</div>
|
||||
<div className="flex justify-center">
|
||||
<Image
|
||||
src="/raven.png"
|
||||
alt="Logotipo Rever Tecnologia"
|
||||
width={110}
|
||||
height={110}
|
||||
className="h-[3.45rem] w-auto"
|
||||
src="/logo-raven.png"
|
||||
alt="Logotipo Raven"
|
||||
width={160}
|
||||
height={160}
|
||||
className="h-16 w-auto"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import { usePathname } from "next/navigation"
|
|||
import Link from "next/link"
|
||||
|
||||
import { SearchForm } from "@/components/search-form"
|
||||
import { VersionSwitcher } from "@/components/version-switcher"
|
||||
import { SidebarBrand } from "@/components/sidebar-brand"
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
|
|
@ -63,57 +63,54 @@ type NavigationGroup = {
|
|||
items: NavigationItem[]
|
||||
}
|
||||
|
||||
const navigation: { versions: string[]; navMain: NavigationGroup[] } = {
|
||||
versions: ["Rever Tecnologia"],
|
||||
navMain: [
|
||||
{
|
||||
title: "Operação",
|
||||
items: [
|
||||
{ title: "Dashboard", url: "/dashboard", icon: LayoutDashboard, requiredRole: "staff" },
|
||||
{
|
||||
title: "Tickets",
|
||||
url: "/tickets",
|
||||
icon: Ticket,
|
||||
requiredRole: "staff",
|
||||
children: [{ title: "Resolvidos", url: "/tickets/resolved", icon: ShieldCheck, requiredRole: "staff" }],
|
||||
},
|
||||
{ title: "Visualizações", url: "/views", icon: PanelsTopLeft, requiredRole: "staff" },
|
||||
{ title: "Modo Play", url: "/play", icon: PlayCircle, requiredRole: "staff" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Relatórios",
|
||||
requiredRole: "staff",
|
||||
items: [
|
||||
{ title: "SLA e produtividade", url: "/reports/sla", icon: TrendingUp, requiredRole: "staff" },
|
||||
{ title: "Qualidade (CSAT)", url: "/reports/csat", icon: LifeBuoy, requiredRole: "staff" },
|
||||
{ title: "Backlog", url: "/reports/backlog", icon: BarChart3, requiredRole: "staff" },
|
||||
{ title: "Horas por cliente", url: "/reports/hours", icon: Clock4, requiredRole: "staff" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Administração",
|
||||
requiredRole: "admin",
|
||||
items: [
|
||||
{
|
||||
title: "Convites e acessos",
|
||||
url: "/admin",
|
||||
icon: UserPlus,
|
||||
requiredRole: "admin",
|
||||
exact: true,
|
||||
},
|
||||
{ title: "Canais & roteamento", url: "/admin/channels", icon: Waypoints, requiredRole: "admin" },
|
||||
{ title: "Times & papéis", url: "/admin/teams", icon: UserCog, requiredRole: "admin" },
|
||||
{ title: "Empresas & clientes", url: "/admin/companies", icon: Building2, requiredRole: "admin" },
|
||||
{ title: "Máquinas", url: "/admin/machines", icon: MonitorCog, requiredRole: "admin" },
|
||||
{ title: "Campos personalizados", url: "/admin/fields", icon: Layers3, requiredRole: "admin" },
|
||||
{ title: "SLAs", url: "/admin/slas", icon: Timer, requiredRole: "admin" },
|
||||
{ title: "Alertas enviados", url: "/admin/alerts", icon: BellRing, requiredRole: "admin" },
|
||||
],
|
||||
},
|
||||
// Removido grupo "Conta" (Configurações) para evitar redundância com o menu do usuário no rodapé
|
||||
],
|
||||
}
|
||||
const navigation: NavigationGroup[] = [
|
||||
{
|
||||
title: "Operação",
|
||||
items: [
|
||||
{ title: "Dashboard", url: "/dashboard", icon: LayoutDashboard, requiredRole: "staff" },
|
||||
{
|
||||
title: "Tickets",
|
||||
url: "/tickets",
|
||||
icon: Ticket,
|
||||
requiredRole: "staff",
|
||||
children: [{ title: "Resolvidos", url: "/tickets/resolved", icon: ShieldCheck, requiredRole: "staff" }],
|
||||
},
|
||||
{ title: "Visualizações", url: "/views", icon: PanelsTopLeft, requiredRole: "staff" },
|
||||
{ title: "Modo Play", url: "/play", icon: PlayCircle, requiredRole: "staff" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Relatórios",
|
||||
requiredRole: "staff",
|
||||
items: [
|
||||
{ title: "SLA e produtividade", url: "/reports/sla", icon: TrendingUp, requiredRole: "staff" },
|
||||
{ title: "Qualidade (CSAT)", url: "/reports/csat", icon: LifeBuoy, requiredRole: "staff" },
|
||||
{ title: "Backlog", url: "/reports/backlog", icon: BarChart3, requiredRole: "staff" },
|
||||
{ title: "Horas por cliente", url: "/reports/hours", icon: Clock4, requiredRole: "staff" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Administração",
|
||||
requiredRole: "admin",
|
||||
items: [
|
||||
{
|
||||
title: "Convites e acessos",
|
||||
url: "/admin",
|
||||
icon: UserPlus,
|
||||
requiredRole: "admin",
|
||||
exact: true,
|
||||
},
|
||||
{ title: "Canais & roteamento", url: "/admin/channels", icon: Waypoints, requiredRole: "admin" },
|
||||
{ title: "Times & papéis", url: "/admin/teams", icon: UserCog, requiredRole: "admin" },
|
||||
{ title: "Empresas & clientes", url: "/admin/companies", icon: Building2, requiredRole: "admin" },
|
||||
{ title: "Máquinas", url: "/admin/machines", icon: MonitorCog, requiredRole: "admin" },
|
||||
{ title: "Campos personalizados", url: "/admin/fields", icon: Layers3, requiredRole: "admin" },
|
||||
{ title: "SLAs", url: "/admin/slas", icon: Timer, requiredRole: "admin" },
|
||||
{ title: "Alertas enviados", url: "/admin/alerts", icon: BellRing, requiredRole: "admin" },
|
||||
],
|
||||
},
|
||||
// Removido grupo "Conta" (Configurações) para evitar redundância com o menu do usuário no rodapé
|
||||
]
|
||||
|
||||
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
const pathname = usePathname()
|
||||
|
|
@ -130,7 +127,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
|||
)
|
||||
const initialExpanded = React.useMemo(() => {
|
||||
const open = new Set<string>()
|
||||
navigation.navMain.forEach((group) => {
|
||||
navigation.forEach((group) => {
|
||||
group.items.forEach((item) => {
|
||||
if (!item.children || item.children.length === 0) return
|
||||
const shouldOpen = item.children.some((child) => {
|
||||
|
|
@ -213,15 +210,16 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
|||
return (
|
||||
<Sidebar {...props}>
|
||||
<SidebarHeader className="gap-3">
|
||||
<VersionSwitcher
|
||||
label="Raven"
|
||||
versions={[...navigation.versions]}
|
||||
defaultVersion={navigation.versions[0]}
|
||||
<SidebarBrand
|
||||
logoSrc="/logo-raven.png"
|
||||
logoAlt="Logotipo Raven"
|
||||
title="Raven"
|
||||
subtitle="Por Rever Tecnologia"
|
||||
/>
|
||||
<SearchForm placeholder="Buscar tickets" />
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
{navigation.navMain.map((group) => {
|
||||
{navigation.map((group) => {
|
||||
if (!canAccess(group.requiredRole)) return null
|
||||
const visibleItems = group.items.filter((item) => canAccess(item.requiredRole))
|
||||
if (visibleItems.length === 0) return null
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
"use client"
|
||||
|
||||
import { type ReactNode, useMemo, useState } from "react"
|
||||
import Image from "next/image"
|
||||
import Link from "next/link"
|
||||
import { usePathname, useRouter } from "next/navigation"
|
||||
import { GalleryVerticalEnd, LogOut, PlusCircle } from "lucide-react"
|
||||
import { LogOut, PlusCircle } from "lucide-react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
|
@ -76,9 +77,16 @@ export function PortalShell({ children }: PortalShellProps) {
|
|||
<header className="border-b border-slate-200 bg-white/90 backdrop-blur">
|
||||
<div className="mx-auto flex w-full max-w-6xl flex-wrap items-center justify-between gap-4 px-6 py-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="flex size-9 items-center justify-center rounded-xl bg-neutral-900 text-white shadow-sm">
|
||||
<GalleryVerticalEnd className="size-4" />
|
||||
</span>
|
||||
<div className="flex h-12 w-12 items-center justify-center">
|
||||
<Image
|
||||
src="/logo-raven.png"
|
||||
alt="Logotipo Raven"
|
||||
width={48}
|
||||
height={48}
|
||||
className="h-12 w-12 object-contain"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm text-neutral-500">
|
||||
Portal do Cliente
|
||||
|
|
|
|||
47
src/components/sidebar-brand.tsx
Normal file
47
src/components/sidebar-brand.tsx
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
"use client"
|
||||
|
||||
import Image from "next/image"
|
||||
|
||||
import {
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
} from "@/components/ui/sidebar"
|
||||
|
||||
interface SidebarBrandProps {
|
||||
logoSrc: string
|
||||
logoAlt: string
|
||||
title: string
|
||||
subtitle: string
|
||||
}
|
||||
|
||||
export function SidebarBrand({ logoSrc, logoAlt, title, subtitle }: SidebarBrandProps) {
|
||||
return (
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton
|
||||
asChild
|
||||
size="lg"
|
||||
className="cursor-default select-none hover:bg-transparent hover:text-inherit active:bg-transparent active:text-inherit focus-visible:ring-0"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-lg">
|
||||
<Image
|
||||
src={logoSrc}
|
||||
alt={logoAlt}
|
||||
width={40}
|
||||
height={40}
|
||||
className="h-10 w-10 object-contain"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5 leading-none">
|
||||
<span className="font-medium">{title}</span>
|
||||
<span className="text-xs text-muted-foreground">{subtitle}</span>
|
||||
</div>
|
||||
</div>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { Check, ChevronsUpDown, GalleryVerticalEnd } from "lucide-react"
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
import {
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
} from "@/components/ui/sidebar"
|
||||
|
||||
type VersionSwitcherProps = {
|
||||
versions: string[]
|
||||
defaultVersion: string
|
||||
label?: string
|
||||
}
|
||||
|
||||
export function VersionSwitcher({
|
||||
versions,
|
||||
defaultVersion,
|
||||
label = "Documentation",
|
||||
}: VersionSwitcherProps) {
|
||||
const [selectedVersion, setSelectedVersion] = React.useState(defaultVersion)
|
||||
|
||||
return (
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<SidebarMenuButton
|
||||
size="lg"
|
||||
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
||||
>
|
||||
<div className="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg">
|
||||
<GalleryVerticalEnd className="size-4" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5 leading-none">
|
||||
<span className="font-medium">{label}</span>
|
||||
<span className="text-xs text-muted-foreground">{selectedVersion}</span>
|
||||
</div>
|
||||
<ChevronsUpDown className="ml-auto" />
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
className="w-(--radix-dropdown-menu-trigger-width)"
|
||||
align="start"
|
||||
>
|
||||
{versions.map((version) => (
|
||||
<DropdownMenuItem
|
||||
key={version}
|
||||
onSelect={() => setSelectedVersion(version)}
|
||||
>
|
||||
{version} {version === selectedVersion && <Check className="ml-auto" />}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue