refactor(settings): reorganize imports and improve code readability

Restructured imports across multiple files to follow a consistent order and improve readability. Also, adjusted some code formatting for better maintainability.
This commit is contained in:
Daniel Luiz Alves
2025-04-11 16:43:51 -03:00
parent 5cd7acc158
commit 6a933891c8
9 changed files with 58 additions and 63 deletions

View File

@@ -1,13 +1,14 @@
"use client"; "use client";
import { useAppInfo } from "@/contexts/app-info-context";
import { removeLogo, uploadLogo } from "@/http/endpoints";
import { Button } from "@/components/ui/button";
import { useTranslations } from "next-intl";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { IconCloudUpload, IconTrash } from "@tabler/icons-react"; import { IconCloudUpload, IconTrash } from "@tabler/icons-react";
import { useTranslations } from "next-intl";
import { toast } from "sonner"; import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { useAppInfo } from "@/contexts/app-info-context";
import { removeLogo, uploadLogo } from "@/http/endpoints";
interface LogoInputProps { interface LogoInputProps {
value?: string; value?: string;
onChange: (value: string) => void; onChange: (value: string) => void;
@@ -15,7 +16,7 @@ interface LogoInputProps {
} }
export function LogoInput({ value, onChange, isDisabled }: LogoInputProps) { export function LogoInput({ value, onChange, isDisabled }: LogoInputProps) {
const t = useTranslations(); const t = useTranslations();
const [isUploading, setIsUploading] = useState(false); const [isUploading, setIsUploading] = useState(false);
const [currentLogo, setCurrentLogo] = useState(value); const [currentLogo, setCurrentLogo] = useState(value);
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
@@ -80,19 +81,9 @@ export function LogoInput({ value, onChange, isDisabled }: LogoInputProps) {
{currentLogo ? ( {currentLogo ? (
<div className="flex flex-col items-center gap-4"> <div className="flex flex-col items-center gap-4">
<div className="relative max-w-[200px] max-h-[200px] flex"> <div className="relative max-w-[200px] max-h-[200px] flex">
<img <img alt={t("logo.labels.appLogo")} className="rounded-lg" src={currentLogo} sizes="200px" />
alt={t("logo.labels.appLogo")}
className="rounded-lg"
src={currentLogo}
sizes="200px"
/>
</div> </div>
<Button <Button variant="destructive" disabled={isDisabled} onClick={handleRemoveLogo}>
variant="destructive"
disabled={isDisabled}
onClick={handleRemoveLogo}
>
{!isUploading && <IconTrash className="mr-2 h-4 w-4" />} {!isUploading && <IconTrash className="mr-2 h-4 w-4" />}
{t("logo.buttons.remove")} {t("logo.buttons.remove")}
</Button> </Button>

View File

@@ -1,5 +1,4 @@
import { ValidGroup } from "../types"; import { SettingsFormProps, ValidGroup } from "../types";
import { SettingsFormProps } from "../types";
import { SettingsGroup } from "./settings-group"; import { SettingsGroup } from "./settings-group";
const GROUP_ORDER: ValidGroup[] = ["general", "email", "security", "storage"]; const GROUP_ORDER: ValidGroup[] = ["general", "email", "security", "storage"];

View File

@@ -1,12 +1,13 @@
import { createGroupMetadata, createFieldDescriptions } from "../constants"; import React from "react";
import { SettingsGroupProps } from "../types"; import { IconChevronDown, IconChevronUp, IconDeviceFloppy } from "@tabler/icons-react";
import { SettingsInput } from "./settings-input"; import { useTranslations } from "next-intl";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader } from "@/components/ui/card"; import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { useTranslations } from "next-intl"; import { createFieldDescriptions, createGroupMetadata } from "../constants";
import React from "react"; import { SettingsGroupProps } from "../types";
import { IconChevronDown, IconChevronUp, IconDeviceFloppy } from "@tabler/icons-react"; import { SettingsInput } from "./settings-input";
export function SettingsGroup({ group, configs, form, isCollapsed, onToggleCollapse, onSubmit }: SettingsGroupProps) { export function SettingsGroup({ group, configs, form, isCollapsed, onToggleCollapse, onSubmit }: SettingsGroupProps) {
const t = useTranslations(); const t = useTranslations();
@@ -21,7 +22,10 @@ export function SettingsGroup({ group, configs, form, isCollapsed, onToggleColla
return ( return (
<form onSubmit={form.handleSubmit(onSubmit)}> <form onSubmit={form.handleSubmit(onSubmit)}>
<Card className="p-6 gap-0"> <Card className="p-6 gap-0">
<CardHeader className="flex flex-row items-center justify-between cursor-pointer p-0" onClick={onToggleCollapse}> <CardHeader
className="flex flex-row items-center justify-between cursor-pointer p-0"
onClick={onToggleCollapse}
>
<div className="flex flex-row items-center gap-8"> <div className="flex flex-row items-center gap-8">
{metadata.icon && React.createElement(metadata.icon, { className: "text-xl text-muted-foreground" })} {metadata.icon && React.createElement(metadata.icon, { className: "text-xl text-muted-foreground" })}
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
@@ -33,7 +37,11 @@ export function SettingsGroup({ group, configs, form, isCollapsed, onToggleColla
</p> </p>
</div> </div>
</div> </div>
{isCollapsed ? <IconChevronDown className="text-muted-foreground" /> : <IconChevronUp className="text-muted-foreground" />} {isCollapsed ? (
<IconChevronDown className="text-muted-foreground" />
) : (
<IconChevronUp className="text-muted-foreground" />
)}
</CardHeader> </CardHeader>
<CardContent className={`${isCollapsed ? "hidden" : "block"} px-0`}> <CardContent className={`${isCollapsed ? "hidden" : "block"} px-0`}>
<Separator className="my-6" /> <Separator className="my-6" />

View File

@@ -1,15 +1,15 @@
import { import Link from "next/link";
Breadcrumb, import { IconLayoutDashboard, IconSettings } from "@tabler/icons-react";
BreadcrumbItem, import { useTranslations } from "next-intl";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink, BreadcrumbLink,
BreadcrumbList, BreadcrumbList,
BreadcrumbSeparator BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"; } from "@/components/ui/breadcrumb";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { useTranslations } from "next-intl";
import { IconSettings } from "@tabler/icons-react";
import { IconLayoutDashboard } from "@tabler/icons-react";
import Link from "next/link";
export function SettingsHeader() { export function SettingsHeader() {
const t = useTranslations(); const t = useTranslations();

View File

@@ -1,10 +1,10 @@
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { UseFormRegister, UseFormWatch } from "react-hook-form";
import { Input } from "@/components/ui/input";
import { createFieldTitles } from "../constants"; import { createFieldTitles } from "../constants";
import { Config } from "../types"; import { Config } from "../types";
import { LogoInput } from "./logo-input"; import { LogoInput } from "./logo-input";
import { Input } from "@/components/ui/input";
import { UseFormRegister, UseFormWatch } from "react-hook-form";
export interface ConfigInputProps { export interface ConfigInputProps {
config: Config; config: Config;

View File

@@ -1,25 +1,25 @@
import { createTranslator } from 'next-intl'; import { IconDatabase, IconMail, IconSettings, IconShield } from "@tabler/icons-react";
import { IconMail, IconSettings, IconShield, IconDatabase } from '@tabler/icons-react'; import { createTranslator } from "next-intl";
export const createGroupMetadata = (t: ReturnType<typeof createTranslator>) => ({ export const createGroupMetadata = (t: ReturnType<typeof createTranslator>) => ({
email: { email: {
title: t('settings.groups.email.title'), title: t("settings.groups.email.title"),
description: t('settings.groups.email.description'), description: t("settings.groups.email.description"),
icon: IconMail, icon: IconMail,
}, },
general: { general: {
title: t('settings.groups.general.title'), title: t("settings.groups.general.title"),
description: t('settings.groups.general.description'), description: t("settings.groups.general.description"),
icon: IconSettings, icon: IconSettings,
}, },
security: { security: {
title: t('settings.groups.security.title'), title: t("settings.groups.security.title"),
description: t('settings.groups.security.description'), description: t("settings.groups.security.description"),
icon: IconShield, icon: IconShield,
}, },
storage: { storage: {
title: t('settings.groups.storage.title'), title: t("settings.groups.storage.title"),
description: t('settings.groups.storage.description'), description: t("settings.groups.storage.description"),
icon: IconDatabase, icon: IconDatabase,
}, },
}); });

View File

@@ -1,28 +1,25 @@
"use client"; "use client";
import { ConfigType, GroupFormData } from "../types";
import { Config } from "../types";
import { useShareContext } from "@/contexts/share-context";
import { useAppInfo } from "@/contexts/app-info-context";
import { getAllConfigs, bulkUpdateConfigs } from "@/http/endpoints";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { zodResolver } from "@hookform/resolvers/zod";
import { useTranslations } from "next-intl";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { useTranslations } from "next-intl";
import { useAppInfo } from "@/contexts/app-info-context";
import { useShareContext } from "@/contexts/share-context";
import { bulkUpdateConfigs, getAllConfigs } from "@/http/endpoints";
import { Config, ConfigType, GroupFormData } from "../types";
const createSchemas = () => ({ const createSchemas = () => ({
settingsSchema: z.object({ settingsSchema: z.object({
configs: z.record( configs: z.record(z.union([z.string(), z.number()]).transform((val) => String(val))),
z.union([z.string(), z.number()]).transform((val) => String(val))
),
}), }),
}); });
export function useSettings() { export function useSettings() {
const t = useTranslations(); const t = useTranslations();
const { settingsSchema } = createSchemas(); const { settingsSchema } = createSchemas();
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [configs, setConfigs] = useState<Record<string, string>>({}); const [configs, setConfigs] = useState<Record<string, string>>({});

View File

@@ -1,4 +1,4 @@
"use client" "use client";
import { ProtectedRoute } from "@/components/auth/protected-route"; import { ProtectedRoute } from "@/components/auth/protected-route";
import { LoadingScreen } from "@/components/layout/loading-screen"; import { LoadingScreen } from "@/components/layout/loading-screen";
@@ -16,7 +16,7 @@ export default function SettingsPage() {
} }
return ( return (
<ProtectedRoute> <ProtectedRoute requireAdmin>
<div className="w-full h-screen flex flex-col"> <div className="w-full h-screen flex flex-col">
<Navbar /> <Navbar />
<div className="flex-1 max-w-7xl mx-auto w-full px-6 py-8"> <div className="flex-1 max-w-7xl mx-auto w-full px-6 py-8">

View File

@@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", "inline-flex items-center cursor-pointer justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{ {
variants: { variants: {
variant: { variant: {