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
31 changes: 17 additions & 14 deletions web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
},
"dependencies": {
"@fontsource-variable/inter": "^5.3.0",
"@phosphor-icons/react": "^2.1.10",
"@hugeicons/core-free-icons": "^4.3.5",
"@hugeicons/react": "^1.1.10",
"@tanstack/react-query": "^5.104.0",
"@tanstack/react-router": "^1.170.40",
"clsx": "^2.1.1",
Expand Down
30 changes: 30 additions & 0 deletions web/src/components/icons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export { HugeiconsIcon } from "@hugeicons/react";
export { default as Activity01Icon } from "@hugeicons/core-free-icons/Activity01Icon";
export { default as Add01Icon } from "@hugeicons/core-free-icons/Add01Icon";
export { default as ArrowDataTransferHorizontalIcon } from "@hugeicons/core-free-icons/ArrowDataTransferHorizontalIcon";
export { default as ArrowRight02Icon } from "@hugeicons/core-free-icons/ArrowRight02Icon";
export { default as BookOpen01Icon } from "@hugeicons/core-free-icons/BookOpen01Icon";
export { default as Cancel01Icon } from "@hugeicons/core-free-icons/Cancel01Icon";
export { default as CreditCardIcon } from "@hugeicons/core-free-icons/CreditCardIcon";
export { default as CustomerSupportIcon } from "@hugeicons/core-free-icons/CustomerSupportIcon";
export { default as DashboardSquare01Icon } from "@hugeicons/core-free-icons/DashboardSquare01Icon";
export { default as FileEditIcon } from "@hugeicons/core-free-icons/FileEditIcon";
export { default as HandshakeIcon } from "@hugeicons/core-free-icons/HandshakeIcon";
export { default as Invoice01Icon } from "@hugeicons/core-free-icons/Invoice01Icon";
export { default as Logout03Icon } from "@hugeicons/core-free-icons/Logout03Icon";
export { default as Megaphone01Icon } from "@hugeicons/core-free-icons/Megaphone01Icon";
export { default as Menu01Icon } from "@hugeicons/core-free-icons/Menu01Icon";
export { default as PackageIcon } from "@hugeicons/core-free-icons/PackageIcon";
export { default as ReturnRequestIcon } from "@hugeicons/core-free-icons/ReturnRequestIcon";
export { default as SecurityCheckIcon } from "@hugeicons/core-free-icons/SecurityCheckIcon";
export { default as ServerStack01Icon } from "@hugeicons/core-free-icons/ServerStack01Icon";
export { default as Settings01Icon } from "@hugeicons/core-free-icons/Settings01Icon";
export { default as ShieldUserIcon } from "@hugeicons/core-free-icons/ShieldUserIcon";
export { default as ShoppingCart01Icon } from "@hugeicons/core-free-icons/ShoppingCart01Icon";
export { default as Tick02Icon } from "@hugeicons/core-free-icons/Tick02Icon";
export { default as UserCircleIcon } from "@hugeicons/core-free-icons/UserCircleIcon";
export { default as UserGroupIcon } from "@hugeicons/core-free-icons/UserGroupIcon";
export { default as UserIcon } from "@hugeicons/core-free-icons/UserIcon";
export { default as ViewIcon } from "@hugeicons/core-free-icons/ViewIcon";
export { default as ViewOffSlashIcon } from "@hugeicons/core-free-icons/ViewOffSlashIcon";
export { default as Wallet01Icon } from "@hugeicons/core-free-icons/Wallet01Icon";
4 changes: 2 additions & 2 deletions web/src/components/toast/toast-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useMemo, useRef, useState, type ReactNode } from "react";
import { X } from "@phosphor-icons/react/X";

import { HugeiconsIcon, Cancel01Icon } from "@/components/icons";
import { ToastContext, type ToastInput, type ToastStatus } from "@/components/toast/use-toast";
import { cn } from "@/lib/utils";

Expand Down Expand Up @@ -56,7 +56,7 @@ export function ToastProvider({ children }: { children: ReactNode }) {
onClick={() => dismissToast(toast.id)}
className="text-muted-foreground hover:text-foreground"
>
<X className="size-3.5" />
<HugeiconsIcon icon={Cancel01Icon} className="size-3.5" />
</button>
</li>
))}
Expand Down
5 changes: 3 additions & 2 deletions web/src/components/ui/checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ReactNode } from "react";
import { Check } from "@phosphor-icons/react/Check";

import { HugeiconsIcon, Tick02Icon } from "@/components/icons";

type CheckboxProps = {
label: ReactNode;
Expand All @@ -19,7 +20,7 @@ export function Checkbox({ label, checked, error, onCheckedChange }: CheckboxPro
onChange={(e) => onCheckedChange(e.target.checked)}
className="peer size-4 cursor-pointer appearance-none border border-input bg-input/30 transition-colors outline-none checked:border-primary checked:bg-primary focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-0"
/>
<Check className="pointer-events-none absolute hidden size-3 text-primary-foreground peer-checked:block" weight="bold" />
<HugeiconsIcon icon={Tick02Icon} className="pointer-events-none absolute hidden size-3 text-primary-foreground peer-checked:block" strokeWidth={3} />
</span>
<span>{label}</span>
</label>
Expand Down
5 changes: 2 additions & 3 deletions web/src/components/ui/input.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useId, useState, type InputHTMLAttributes } from "react";
import { Eye } from "@phosphor-icons/react/Eye";
import { EyeSlash } from "@phosphor-icons/react/EyeSlash";

import { HugeiconsIcon, ViewIcon, ViewOffSlashIcon } from "@/components/icons";
import { cn } from "@/lib/utils";

interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
Expand Down Expand Up @@ -36,7 +35,7 @@ export function Input({ error, className, id: idProp, type, ...props }: InputPro
onClick={() => setRevealed((prev) => !prev)}
className="absolute top-1/2 right-1 flex size-8 -translate-y-1/2 items-center justify-center text-muted-foreground hover:text-foreground"
>
{revealed ? <EyeSlash className="size-4" /> : <Eye className="size-4" />}
{revealed ? <HugeiconsIcon icon={ViewOffSlashIcon} className="size-4" /> : <HugeiconsIcon icon={ViewIcon} className="size-4" />}
</button>
)}
</div>
Expand Down
9 changes: 3 additions & 6 deletions web/src/routes/__root.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { QueryClient } from "@tanstack/react-query";
import { IconContext } from "@phosphor-icons/react/dist/lib/context";
import { Outlet, createRootRouteWithContext } from "@tanstack/react-router";

import { ToastProvider } from "@/components/toast/toast-provider";
Expand All @@ -11,10 +10,8 @@ export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()(

function RootLayout() {
return (
<IconContext value={{ weight: "light" }}>
<ToastProvider>
<Outlet />
</ToastProvider>
</IconContext>
<ToastProvider>
<Outlet />
</ToastProvider>
);
}
30 changes: 11 additions & 19 deletions web/src/routes/admin/route.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { Link, Outlet, createFileRoute, redirect } from "@tanstack/react-router";
import { ArrowUUpLeft } from "@phosphor-icons/react/ArrowUUpLeft";
import { GearSix } from "@phosphor-icons/react/GearSix";
import { HardDrives } from "@phosphor-icons/react/HardDrives";
import { Package } from "@phosphor-icons/react/Package";
import { Receipt } from "@phosphor-icons/react/Receipt";
import { SignOut } from "@phosphor-icons/react/SignOut";
import { SquaresFour } from "@phosphor-icons/react/SquaresFour";
import { User } from "@phosphor-icons/react/User";
import { UsersThree } from "@phosphor-icons/react/UsersThree";

import { meQuery } from "@/api/auth/me";
import { Permission } from "@/api/auth/permissions";
import { HugeiconsIcon, DashboardSquare01Icon, Invoice01Icon, Logout03Icon, PackageIcon, ReturnRequestIcon, ServerStack01Icon, Settings01Icon, UserGroupIcon, UserIcon } from "@/components/icons";

export const Route = createFileRoute("/admin")({
beforeLoad: async ({ context, location }) => {
Expand All @@ -28,15 +20,15 @@ export const Route = createFileRoute("/admin")({

const NAV_GROUPS = [
[
{ label: "Overview", to: "/admin", icon: SquaresFour },
{ label: "Clients", to: "/admin/clients", icon: UsersThree, permission: Permission.ClientsView },
{ label: "Products", to: "/admin/products", icon: Package, permission: Permission.ProductsManage },
{ label: "Services", to: "/admin/services", icon: HardDrives, permission: Permission.ServicesManage },
{ label: "Invoices", to: "/admin/invoices", icon: Receipt, permission: Permission.InvoicesManage },
{ label: "Refunds", to: "/admin/refunds", icon: ArrowUUpLeft, permission: Permission.PaymentsRefund },
{ label: "Settings", to: "/admin/settings", icon: GearSix, permission: Permission.SettingsManage },
{ label: "Overview", to: "/admin", icon: DashboardSquare01Icon },
{ label: "Clients", to: "/admin/clients", icon: UserGroupIcon, permission: Permission.ClientsView },
{ label: "Products", to: "/admin/products", icon: PackageIcon, permission: Permission.ProductsManage },
{ label: "Services", to: "/admin/services", icon: ServerStack01Icon, permission: Permission.ServicesManage },
{ label: "Invoices", to: "/admin/invoices", icon: Invoice01Icon, permission: Permission.InvoicesManage },
{ label: "Refunds", to: "/admin/refunds", icon: ReturnRequestIcon, permission: Permission.PaymentsRefund },
{ label: "Settings", to: "/admin/settings", icon: Settings01Icon, permission: Permission.SettingsManage },
],
[{ label: "Client area", to: "/client", icon: User }],
[{ label: "Client area", to: "/client", icon: UserIcon }],
] as const;

function AdminLayout() {
Expand Down Expand Up @@ -68,7 +60,7 @@ function AdminLayout() {
title="Sign out"
className="grid size-8 place-items-center text-muted-foreground transition-colors hover:text-foreground"
>
<SignOut className="size-4" />
<HugeiconsIcon icon={Logout03Icon} className="size-4" />
</Link>
</div>
</header>
Expand All @@ -88,7 +80,7 @@ function AdminLayout() {
aria-label={item.label}
className="group relative grid size-8 place-items-center border border-transparent text-muted-foreground transition-colors hover:bg-muted hover:text-foreground data-[status=active]:border-border data-[status=active]:bg-muted data-[status=active]:text-foreground"
>
<item.icon className="size-4" />
<HugeiconsIcon icon={item.icon} className="size-4" />
<span
aria-hidden="true"
className="pointer-events-none absolute top-1/2 left-full z-50 ml-2 -translate-y-1/2 bg-foreground px-2 py-1 text-xs font-medium whitespace-nowrap text-background opacity-0 shadow-md transition-opacity duration-300 group-hover:opacity-100 group-focus-visible:opacity-100"
Expand Down
57 changes: 20 additions & 37 deletions web/src/routes/client/route.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,9 @@
import { Link, Outlet, createFileRoute, redirect, useRouterState } from "@tanstack/react-router";
import { ArrowsLeftRight } from "@phosphor-icons/react/ArrowsLeftRight";
import { BookOpen } from "@phosphor-icons/react/BookOpen";
import { CreditCard } from "@phosphor-icons/react/CreditCard";
import { FileText } from "@phosphor-icons/react/FileText";
import { Handshake } from "@phosphor-icons/react/Handshake";
import { HardDrives } from "@phosphor-icons/react/HardDrives";
import { Lifebuoy } from "@phosphor-icons/react/Lifebuoy";
import { Megaphone } from "@phosphor-icons/react/Megaphone";
import { Plus } from "@phosphor-icons/react/Plus";
import { Pulse } from "@phosphor-icons/react/Pulse";
import { Receipt } from "@phosphor-icons/react/Receipt";
import { ShieldCheck } from "@phosphor-icons/react/ShieldCheck";
import { ShieldStar } from "@phosphor-icons/react/ShieldStar";
import { ShoppingCart } from "@phosphor-icons/react/ShoppingCart";
import { SignOut } from "@phosphor-icons/react/SignOut";
import { SquaresFour } from "@phosphor-icons/react/SquaresFour";
import { UserCircle } from "@phosphor-icons/react/UserCircle";
import { Wallet } from "@phosphor-icons/react/Wallet";

import { meQuery } from "@/api/auth/me";
import { Permission } from "@/api/auth/permissions";
import { TEMP_SERVICES, type ServiceStatus } from "@/api/services/services";
import { HugeiconsIcon, Activity01Icon, Add01Icon, ArrowDataTransferHorizontalIcon, BookOpen01Icon, CreditCardIcon, CustomerSupportIcon, DashboardSquare01Icon, FileEditIcon, HandshakeIcon, Invoice01Icon, Logout03Icon, Megaphone01Icon, SecurityCheckIcon, ServerStack01Icon, ShieldUserIcon, ShoppingCart01Icon, UserCircleIcon, Wallet01Icon } from "@/components/icons";
import { cn } from "@/lib/utils";

export const Route = createFileRoute("/client")({
Expand All @@ -36,28 +19,28 @@ export const Route = createFileRoute("/client")({

const NAV_GROUPS = [
[
{ label: "Overview", to: "/client", icon: SquaresFour },
{ label: "Services", to: "/client/services", icon: HardDrives },
{ label: "Invoices", to: "/client/invoices", icon: Receipt },
{ label: "Store", to: "/client/store", icon: ShoppingCart },
{ label: "Support tickets", to: "/client/tickets", icon: Lifebuoy },
{ label: "Overview", to: "/client", icon: DashboardSquare01Icon },
{ label: "Services", to: "/client/services", icon: ServerStack01Icon },
{ label: "Invoices", to: "/client/invoices", icon: Invoice01Icon },
{ label: "Store", to: "/client/store", icon: ShoppingCart01Icon },
{ label: "Support tickets", to: "/client/tickets", icon: CustomerSupportIcon },
],
[
{ label: "Quotes", to: "/client/quotes", icon: FileText },
{ label: "Transactions", to: "/client/transactions", icon: ArrowsLeftRight },
{ label: "Add funds", to: "/client/credit", icon: Wallet },
{ label: "Payment methods", to: "/client/payment-methods", icon: CreditCard },
{ label: "Quotes", to: "/client/quotes", icon: FileEditIcon },
{ label: "Transactions", to: "/client/transactions", icon: ArrowDataTransferHorizontalIcon },
{ label: "Add funds", to: "/client/credit", icon: Wallet01Icon },
{ label: "Payment methods", to: "/client/payment-methods", icon: CreditCardIcon },
],
[
{ label: "Announcements", to: "/client/announcements", icon: Megaphone },
{ label: "Knowledge base", to: "/client/knowledge-base", icon: BookOpen },
{ label: "Network status", to: "/client/network-status", icon: Pulse },
{ label: "Affiliates", to: "/client/affiliates", icon: Handshake },
{ label: "Announcements", to: "/client/announcements", icon: Megaphone01Icon },
{ label: "Knowledge base", to: "/client/knowledge-base", icon: BookOpen01Icon },
{ label: "Network status", to: "/client/network-status", icon: Activity01Icon },
{ label: "Affiliates", to: "/client/affiliates", icon: HandshakeIcon },
],
[
{ label: "Admin area", to: "/admin", icon: ShieldStar, permission: Permission.AccessPanel },
{ label: "Security", to: "/client/security", icon: ShieldCheck },
{ label: "Account", to: "/client/account", icon: UserCircle },
{ label: "Admin area", to: "/admin", icon: ShieldUserIcon, permission: Permission.AccessPanel },
{ label: "Security", to: "/client/security", icon: SecurityCheckIcon },
{ label: "Account", to: "/client/account", icon: UserCircleIcon },
],
] as const;

Expand Down Expand Up @@ -97,7 +80,7 @@ function ClientLayout() {
title="Sign out"
className="grid size-8 place-items-center text-muted-foreground transition-colors hover:text-foreground"
>
<SignOut className="size-4" />
<HugeiconsIcon icon={Logout03Icon} className="size-4" />
</Link>
</div>
</header>
Expand All @@ -117,7 +100,7 @@ function ClientLayout() {
aria-label={item.label}
className="group relative grid size-8 place-items-center border border-transparent text-muted-foreground transition-colors hover:bg-muted hover:text-foreground data-[status=active]:border-border data-[status=active]:bg-muted data-[status=active]:text-foreground"
>
<item.icon className="size-4" />
<HugeiconsIcon icon={item.icon} className="size-4" />
<span
aria-hidden="true"
className="pointer-events-none absolute top-1/2 left-full z-50 ml-2 -translate-y-1/2 bg-foreground px-2 py-1 text-xs font-medium whitespace-nowrap text-background opacity-0 shadow-md transition-opacity duration-300 group-hover:opacity-100 group-focus-visible:opacity-100"
Expand All @@ -141,7 +124,7 @@ function ClientLayout() {
title="Order a service"
className="ml-auto grid size-7 place-items-center text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
>
<Plus className="size-4" />
<HugeiconsIcon icon={Add01Icon} className="size-4" />
</Link>
</div>
<div className="flex flex-col overflow-y-auto">
Expand Down
8 changes: 3 additions & 5 deletions web/src/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { useQuery } from "@tanstack/react-query";
import { Link, createFileRoute } from "@tanstack/react-router";
import { useState } from "react";
import { ArrowRight } from "@phosphor-icons/react/ArrowRight";
import { List } from "@phosphor-icons/react/List";
import { X } from "@phosphor-icons/react/X";

import { meQuery } from "@/api/auth/me";
import { HugeiconsIcon, ArrowRight02Icon, Cancel01Icon, Menu01Icon } from "@/components/icons";

export const Route = createFileRoute("/")({
component: Index,
Expand Down Expand Up @@ -49,7 +47,7 @@ function Index() {
className="inline-flex h-8 items-center gap-2 border border-primary/45 bg-primary/12 pr-2.5 pl-3 text-[13px] font-medium transition-all hover:border-primary/70 hover:bg-primary/22 active:translate-y-px"
>
{user ? "Dashboard" : "Sign in"}
<ArrowRight className="size-4" />
<HugeiconsIcon icon={ArrowRight02Icon} className="size-4" />
</Link>

<button
Expand All @@ -60,7 +58,7 @@ function Index() {
onClick={() => setMenuOpen((prev) => !prev)}
className="-mr-2 flex size-10 items-center justify-center text-muted-foreground transition-colors hover:text-foreground sm:hidden"
>
{menuOpen ? <X className="size-5" /> : <List className="size-5" />}
{menuOpen ? <HugeiconsIcon icon={Cancel01Icon} className="size-5" /> : <HugeiconsIcon icon={Menu01Icon} className="size-5" />}
</button>
</div>
</div>
Expand Down
Loading
Loading