refactor: Standardize string literals to use double quotes and apply minor formatting across tenant management and settings components.
This commit is contained in:
parent
f460a89201
commit
1025504a55
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,17 @@
|
|||||||
import { Layout } from '@/components/layout/Layout';
|
import { Layout } from "@/components/layout/Layout";
|
||||||
import { ImageIcon, Loader2, X } from 'lucide-react';
|
import { ImageIcon, Loader2, X } from "lucide-react";
|
||||||
import { useState, useEffect, type ReactElement } from 'react';
|
import { useState, useEffect, type ReactElement } from "react";
|
||||||
import { useAppSelector, useAppDispatch } from '@/hooks/redux-hooks';
|
import { useAppSelector, useAppDispatch } from "@/hooks/redux-hooks";
|
||||||
import { tenantService } from '@/services/tenant-service';
|
import { tenantService } from "@/services/tenant-service";
|
||||||
import { fileService } from '@/services/file-service';
|
import { fileService } from "@/services/file-service";
|
||||||
import { showToast } from '@/utils/toast';
|
import { showToast } from "@/utils/toast";
|
||||||
import { updateTheme } from '@/store/themeSlice';
|
import { updateTheme } from "@/store/themeSlice";
|
||||||
import { PrimaryButton, AuthenticatedImage } from '@/components/shared';
|
import { PrimaryButton, AuthenticatedImage } from "@/components/shared";
|
||||||
import type { Tenant } from '@/types/tenant';
|
import type { Tenant } from "@/types/tenant";
|
||||||
|
|
||||||
// Helper function to get base URL with protocol
|
// Helper function to get base URL with protocol
|
||||||
const getBaseUrlWithProtocol = (): string => {
|
const getBaseUrlWithProtocol = (): string => {
|
||||||
return import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000';
|
return import.meta.env.VITE_API_BASE_URL || "http://localhost:3000";
|
||||||
};
|
};
|
||||||
|
|
||||||
const Settings = (): ReactElement => {
|
const Settings = (): ReactElement => {
|
||||||
@ -26,14 +26,16 @@ const Settings = (): ReactElement => {
|
|||||||
const [tenant, setTenant] = useState<Tenant | null>(null);
|
const [tenant, setTenant] = useState<Tenant | null>(null);
|
||||||
|
|
||||||
// Color states
|
// Color states
|
||||||
const [primaryColor, setPrimaryColor] = useState<string>('#112868');
|
const [primaryColor, setPrimaryColor] = useState<string>("#112868");
|
||||||
const [secondaryColor, setSecondaryColor] = useState<string>('#23DCE1');
|
const [secondaryColor, setSecondaryColor] = useState<string>("#23DCE1");
|
||||||
const [accentColor, setAccentColor] = useState<string>('#084CC8');
|
const [accentColor, setAccentColor] = useState<string>("#084CC8");
|
||||||
|
|
||||||
// Logo states
|
// Logo states
|
||||||
const [logoFile, setLogoFile] = useState<File | null>(null);
|
const [logoFile, setLogoFile] = useState<File | null>(null);
|
||||||
const [logoFilePath, setLogoFilePath] = useState<string | null>(null);
|
const [logoFilePath, setLogoFilePath] = useState<string | null>(null);
|
||||||
const [logoFileAttachmentUuid, setLogoFileAttachmentUuid] = useState<string | null>(null);
|
const [logoFileAttachmentUuid, setLogoFileAttachmentUuid] = useState<
|
||||||
|
string | null
|
||||||
|
>(null);
|
||||||
const [logoFileUrl, setLogoFileUrl] = useState<string | null>(null);
|
const [logoFileUrl, setLogoFileUrl] = useState<string | null>(null);
|
||||||
const [logoPreviewUrl, setLogoPreviewUrl] = useState<string | null>(null);
|
const [logoPreviewUrl, setLogoPreviewUrl] = useState<string | null>(null);
|
||||||
const [isUploadingLogo, setIsUploadingLogo] = useState<boolean>(false);
|
const [isUploadingLogo, setIsUploadingLogo] = useState<boolean>(false);
|
||||||
@ -41,9 +43,13 @@ const Settings = (): ReactElement => {
|
|||||||
// Favicon states
|
// Favicon states
|
||||||
const [faviconFile, setFaviconFile] = useState<File | null>(null);
|
const [faviconFile, setFaviconFile] = useState<File | null>(null);
|
||||||
const [faviconFilePath, setFaviconFilePath] = useState<string | null>(null);
|
const [faviconFilePath, setFaviconFilePath] = useState<string | null>(null);
|
||||||
const [faviconFileAttachmentUuid, setFaviconFileAttachmentUuid] = useState<string | null>(null);
|
const [faviconFileAttachmentUuid, setFaviconFileAttachmentUuid] = useState<
|
||||||
|
string | null
|
||||||
|
>(null);
|
||||||
const [faviconFileUrl, setFaviconFileUrl] = useState<string | null>(null);
|
const [faviconFileUrl, setFaviconFileUrl] = useState<string | null>(null);
|
||||||
const [faviconPreviewUrl, setFaviconPreviewUrl] = useState<string | null>(null);
|
const [faviconPreviewUrl, setFaviconPreviewUrl] = useState<string | null>(
|
||||||
|
null,
|
||||||
|
);
|
||||||
const [isUploadingFavicon, setIsUploadingFavicon] = useState<boolean>(false);
|
const [isUploadingFavicon, setIsUploadingFavicon] = useState<boolean>(false);
|
||||||
const [logoError, setLogoError] = useState<string | null>(null);
|
const [logoError, setLogoError] = useState<string | null>(null);
|
||||||
const [faviconError, setFaviconError] = useState<string | null>(null);
|
const [faviconError, setFaviconError] = useState<string | null>(null);
|
||||||
@ -52,7 +58,7 @@ const Settings = (): ReactElement => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchTenant = async (): Promise<void> => {
|
const fetchTenant = async (): Promise<void> => {
|
||||||
if (!tenantId) {
|
if (!tenantId) {
|
||||||
setError('Tenant ID not found');
|
setError("Tenant ID not found");
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -67,15 +73,17 @@ const Settings = (): ReactElement => {
|
|||||||
setTenant(tenantData);
|
setTenant(tenantData);
|
||||||
|
|
||||||
// Set colors
|
// Set colors
|
||||||
setPrimaryColor(tenantData.primary_color || '#112868');
|
setPrimaryColor(tenantData.primary_color || "#112868");
|
||||||
setSecondaryColor(tenantData.secondary_color || '#23DCE1');
|
setSecondaryColor(tenantData.secondary_color || "#23DCE1");
|
||||||
setAccentColor(tenantData.accent_color || '#084CC8');
|
setAccentColor(tenantData.accent_color || "#084CC8");
|
||||||
|
|
||||||
// Set logo
|
// Set logo
|
||||||
if (tenantData.logo_file_path) {
|
if (tenantData.logo_file_path) {
|
||||||
setLogoFileUrl(tenantData.logo_file_path);
|
setLogoFileUrl(tenantData.logo_file_path);
|
||||||
setLogoFilePath(tenantData.logo_file_path);
|
setLogoFilePath(tenantData.logo_file_path);
|
||||||
setLogoFileAttachmentUuid(tenantData.logo_file_attachment_uuid || null);
|
setLogoFileAttachmentUuid(
|
||||||
|
tenantData.logo_file_attachment_uuid || null,
|
||||||
|
);
|
||||||
setLogoError(null);
|
setLogoError(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +91,9 @@ const Settings = (): ReactElement => {
|
|||||||
if (tenantData.favicon_file_path) {
|
if (tenantData.favicon_file_path) {
|
||||||
setFaviconFileUrl(tenantData.favicon_file_path);
|
setFaviconFileUrl(tenantData.favicon_file_path);
|
||||||
setFaviconFilePath(tenantData.favicon_file_path);
|
setFaviconFilePath(tenantData.favicon_file_path);
|
||||||
setFaviconFileAttachmentUuid(tenantData.favicon_file_attachment_uuid || null);
|
setFaviconFileAttachmentUuid(
|
||||||
|
tenantData.favicon_file_attachment_uuid || null,
|
||||||
|
);
|
||||||
setFaviconError(null);
|
setFaviconError(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,7 +102,7 @@ const Settings = (): ReactElement => {
|
|||||||
err?.response?.data?.error?.message ||
|
err?.response?.data?.error?.message ||
|
||||||
err?.response?.data?.message ||
|
err?.response?.data?.message ||
|
||||||
err?.message ||
|
err?.message ||
|
||||||
'Failed to load tenant settings';
|
"Failed to load tenant settings";
|
||||||
setError(errorMessage);
|
setError(errorMessage);
|
||||||
showToast.error(errorMessage);
|
showToast.error(errorMessage);
|
||||||
} finally {
|
} finally {
|
||||||
@ -115,20 +125,27 @@ const Settings = (): ReactElement => {
|
|||||||
};
|
};
|
||||||
}, [logoPreviewUrl, faviconPreviewUrl]);
|
}, [logoPreviewUrl, faviconPreviewUrl]);
|
||||||
|
|
||||||
const handleLogoChange = async (e: React.ChangeEvent<HTMLInputElement>): Promise<void> => {
|
const handleLogoChange = async (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement>,
|
||||||
|
): Promise<void> => {
|
||||||
const file = e.target.files?.[0];
|
const file = e.target.files?.[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
// Validate file size (2MB max)
|
// Validate file size (2MB max)
|
||||||
if (file.size > 2 * 1024 * 1024) {
|
if (file.size > 2 * 1024 * 1024) {
|
||||||
showToast.error('Logo file size must be less than 2MB');
|
showToast.error("Logo file size must be less than 2MB");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate file type
|
// Validate file type
|
||||||
const validTypes = ['image/png', 'image/svg+xml', 'image/jpeg', 'image/jpg'];
|
const validTypes = [
|
||||||
|
"image/png",
|
||||||
|
"image/svg+xml",
|
||||||
|
"image/jpeg",
|
||||||
|
"image/jpg",
|
||||||
|
];
|
||||||
if (!validTypes.includes(file.type)) {
|
if (!validTypes.includes(file.type)) {
|
||||||
showToast.error('Logo must be PNG, SVG, or JPG format');
|
showToast.error("Logo must be PNG, SVG, or JPG format");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +160,12 @@ const Settings = (): ReactElement => {
|
|||||||
setIsUploadingLogo(true);
|
setIsUploadingLogo(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fileService.upload(file, 'tenant', tenantId || undefined);
|
const response = await fileService.upload(
|
||||||
|
file,
|
||||||
|
"tenant",
|
||||||
|
crypto.randomUUID(),
|
||||||
|
tenantId || undefined,
|
||||||
|
);
|
||||||
const fileId = response.data.id;
|
const fileId = response.data.id;
|
||||||
setLogoFileAttachmentUuid(fileId);
|
setLogoFileAttachmentUuid(fileId);
|
||||||
|
|
||||||
@ -153,13 +175,13 @@ const Settings = (): ReactElement => {
|
|||||||
setLogoFileUrl(formattedUrl);
|
setLogoFileUrl(formattedUrl);
|
||||||
|
|
||||||
setLogoError(null);
|
setLogoError(null);
|
||||||
showToast.success('Logo uploaded successfully');
|
showToast.success("Logo uploaded successfully");
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const errorMessage =
|
const errorMessage =
|
||||||
err?.response?.data?.error?.message ||
|
err?.response?.data?.error?.message ||
|
||||||
err?.response?.data?.message ||
|
err?.response?.data?.message ||
|
||||||
err?.message ||
|
err?.message ||
|
||||||
'Failed to upload logo. Please try again.';
|
"Failed to upload logo. Please try again.";
|
||||||
showToast.error(errorMessage);
|
showToast.error(errorMessage);
|
||||||
setLogoFile(null);
|
setLogoFile(null);
|
||||||
URL.revokeObjectURL(previewUrl);
|
URL.revokeObjectURL(previewUrl);
|
||||||
@ -172,20 +194,26 @@ const Settings = (): ReactElement => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFaviconChange = async (e: React.ChangeEvent<HTMLInputElement>): Promise<void> => {
|
const handleFaviconChange = async (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement>,
|
||||||
|
): Promise<void> => {
|
||||||
const file = e.target.files?.[0];
|
const file = e.target.files?.[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
// Validate file size (500KB max)
|
// Validate file size (500KB max)
|
||||||
if (file.size > 500 * 1024) {
|
if (file.size > 500 * 1024) {
|
||||||
showToast.error('Favicon file size must be less than 500KB');
|
showToast.error("Favicon file size must be less than 500KB");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate file type
|
// Validate file type
|
||||||
const validTypes = ['image/x-icon', 'image/png', 'image/vnd.microsoft.icon'];
|
const validTypes = [
|
||||||
|
"image/x-icon",
|
||||||
|
"image/png",
|
||||||
|
"image/vnd.microsoft.icon",
|
||||||
|
];
|
||||||
if (!validTypes.includes(file.type)) {
|
if (!validTypes.includes(file.type)) {
|
||||||
showToast.error('Favicon must be ICO or PNG format');
|
showToast.error("Favicon must be ICO or PNG format");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +228,12 @@ const Settings = (): ReactElement => {
|
|||||||
setIsUploadingFavicon(true);
|
setIsUploadingFavicon(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fileService.upload(file, 'tenant', tenantId || undefined);
|
const response = await fileService.upload(
|
||||||
|
file,
|
||||||
|
"tenant",
|
||||||
|
crypto.randomUUID(),
|
||||||
|
tenantId || undefined,
|
||||||
|
);
|
||||||
const fileId = response.data.id;
|
const fileId = response.data.id;
|
||||||
setFaviconFileAttachmentUuid(fileId);
|
setFaviconFileAttachmentUuid(fileId);
|
||||||
|
|
||||||
@ -210,13 +243,13 @@ const Settings = (): ReactElement => {
|
|||||||
setFaviconFileUrl(formattedUrl);
|
setFaviconFileUrl(formattedUrl);
|
||||||
|
|
||||||
setFaviconError(null);
|
setFaviconError(null);
|
||||||
showToast.success('Favicon uploaded successfully');
|
showToast.success("Favicon uploaded successfully");
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const errorMessage =
|
const errorMessage =
|
||||||
err?.response?.data?.error?.message ||
|
err?.response?.data?.error?.message ||
|
||||||
err?.response?.data?.message ||
|
err?.response?.data?.message ||
|
||||||
err?.message ||
|
err?.message ||
|
||||||
'Failed to upload favicon. Please try again.';
|
"Failed to upload favicon. Please try again.";
|
||||||
showToast.error(errorMessage);
|
showToast.error(errorMessage);
|
||||||
setFaviconFile(null);
|
setFaviconFile(null);
|
||||||
URL.revokeObjectURL(previewUrl);
|
URL.revokeObjectURL(previewUrl);
|
||||||
@ -240,9 +273,11 @@ const Settings = (): ReactElement => {
|
|||||||
setLogoFileAttachmentUuid(null);
|
setLogoFileAttachmentUuid(null);
|
||||||
setLogoError(null);
|
setLogoError(null);
|
||||||
// Reset the file input
|
// Reset the file input
|
||||||
const fileInput = document.getElementById('logo-upload') as HTMLInputElement;
|
const fileInput = document.getElementById(
|
||||||
|
"logo-upload",
|
||||||
|
) as HTMLInputElement;
|
||||||
if (fileInput) {
|
if (fileInput) {
|
||||||
fileInput.value = '';
|
fileInput.value = "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -257,9 +292,11 @@ const Settings = (): ReactElement => {
|
|||||||
setFaviconFileAttachmentUuid(null);
|
setFaviconFileAttachmentUuid(null);
|
||||||
setFaviconError(null);
|
setFaviconError(null);
|
||||||
// Reset the file input
|
// Reset the file input
|
||||||
const fileInput = document.getElementById('favicon-upload') as HTMLInputElement;
|
const fileInput = document.getElementById(
|
||||||
|
"favicon-upload",
|
||||||
|
) as HTMLInputElement;
|
||||||
if (fileInput) {
|
if (fileInput) {
|
||||||
fileInput.value = '';
|
fileInput.value = "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -274,11 +311,11 @@ const Settings = (): ReactElement => {
|
|||||||
const isFaviconMissing = !faviconFilePath;
|
const isFaviconMissing = !faviconFilePath;
|
||||||
|
|
||||||
if (isLogoMissing) {
|
if (isLogoMissing) {
|
||||||
setLogoError('Logo is required');
|
setLogoError("Logo is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFaviconMissing) {
|
if (isFaviconMissing) {
|
||||||
setFaviconError('Favicon is required');
|
setFaviconError("Favicon is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLogoMissing || isFaviconMissing) {
|
if (isLogoMissing || isFaviconMissing) {
|
||||||
@ -290,8 +327,10 @@ const Settings = (): ReactElement => {
|
|||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
// Build update data matching EditTenantModal format
|
// Build update data matching EditTenantModal format
|
||||||
const existingSettings = (tenant.settings as Record<string, unknown>) || {};
|
const existingSettings =
|
||||||
const existingContact = (existingSettings.contact as Record<string, unknown>) || {};
|
(tenant.settings as Record<string, unknown>) || {};
|
||||||
|
const existingContact =
|
||||||
|
(existingSettings.contact as Record<string, unknown>) || {};
|
||||||
|
|
||||||
const updateData = {
|
const updateData = {
|
||||||
name: tenant.name,
|
name: tenant.name,
|
||||||
@ -312,7 +351,8 @@ const Settings = (): ReactElement => {
|
|||||||
logo_file_path: logoFilePath || undefined,
|
logo_file_path: logoFilePath || undefined,
|
||||||
logo_file_attachment_uuid: logoFileAttachmentUuid || undefined,
|
logo_file_attachment_uuid: logoFileAttachmentUuid || undefined,
|
||||||
favicon_file_path: faviconFilePath || undefined,
|
favicon_file_path: faviconFilePath || undefined,
|
||||||
favicon_file_attachment_uuid: faviconFileAttachmentUuid || undefined,
|
favicon_file_attachment_uuid:
|
||||||
|
faviconFileAttachmentUuid || undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -320,7 +360,7 @@ const Settings = (): ReactElement => {
|
|||||||
const response = await tenantService.update(tenantId, updateData);
|
const response = await tenantService.update(tenantId, updateData);
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
showToast.success('Settings updated successfully');
|
showToast.success("Settings updated successfully");
|
||||||
|
|
||||||
// Update theme in Redux
|
// Update theme in Redux
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -330,7 +370,7 @@ const Settings = (): ReactElement => {
|
|||||||
primary_color: primaryColor,
|
primary_color: primaryColor,
|
||||||
secondary_color: secondaryColor,
|
secondary_color: secondaryColor,
|
||||||
accent_color: accentColor,
|
accent_color: accentColor,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update local tenant state
|
// Update local tenant state
|
||||||
@ -350,7 +390,7 @@ const Settings = (): ReactElement => {
|
|||||||
err?.response?.data?.error?.message ||
|
err?.response?.data?.error?.message ||
|
||||||
err?.response?.data?.message ||
|
err?.response?.data?.message ||
|
||||||
err?.message ||
|
err?.message ||
|
||||||
'Failed to update settings. Please try again.';
|
"Failed to update settings. Please try again.";
|
||||||
setError(errorMessage);
|
setError(errorMessage);
|
||||||
showToast.error(errorMessage);
|
showToast.error(errorMessage);
|
||||||
} finally {
|
} finally {
|
||||||
@ -363,8 +403,8 @@ const Settings = (): ReactElement => {
|
|||||||
<Layout
|
<Layout
|
||||||
currentPage="Settings"
|
currentPage="Settings"
|
||||||
pageHeader={{
|
pageHeader={{
|
||||||
title: 'Settings',
|
title: "Settings",
|
||||||
description: 'Manage your tenant settings',
|
description: "Manage your tenant settings",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-center py-12">
|
<div className="flex items-center justify-center py-12">
|
||||||
@ -379,8 +419,8 @@ const Settings = (): ReactElement => {
|
|||||||
<Layout
|
<Layout
|
||||||
currentPage="Settings"
|
currentPage="Settings"
|
||||||
pageHeader={{
|
pageHeader={{
|
||||||
title: 'Settings',
|
title: "Settings",
|
||||||
description: 'Manage your tenant settings',
|
description: "Manage your tenant settings",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="p-4 bg-[rgba(239,68,68,0.1)] border border-[#ef4444] rounded-md">
|
<div className="p-4 bg-[rgba(239,68,68,0.1)] border border-[#ef4444] rounded-md">
|
||||||
@ -394,8 +434,8 @@ const Settings = (): ReactElement => {
|
|||||||
<Layout
|
<Layout
|
||||||
currentPage="Settings"
|
currentPage="Settings"
|
||||||
pageHeader={{
|
pageHeader={{
|
||||||
title: 'Settings',
|
title: "Settings",
|
||||||
description: 'Manage your tenant settings',
|
description: "Manage your tenant settings",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6">
|
||||||
@ -434,8 +474,12 @@ const Settings = (): ReactElement => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-0.5 flex-1 min-w-0">
|
<div className="flex flex-col gap-0.5 flex-1 min-w-0">
|
||||||
<span className="text-sm font-medium text-[#0f1724]">Upload Logo</span>
|
<span className="text-sm font-medium text-[#0f1724]">
|
||||||
<span className="text-xs font-normal text-[#9ca3af]">PNG, SVG, JPG up to 2MB.</span>
|
Upload Logo
|
||||||
|
</span>
|
||||||
|
<span className="text-xs font-normal text-[#9ca3af]">
|
||||||
|
PNG, SVG, JPG up to 2MB.
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
id="logo-upload"
|
id="logo-upload"
|
||||||
@ -453,7 +497,9 @@ const Settings = (): ReactElement => {
|
|||||||
<div className="flex flex-col gap-2 mt-1">
|
<div className="flex flex-col gap-2 mt-1">
|
||||||
{logoFile && (
|
{logoFile && (
|
||||||
<div className="text-xs text-[#6b7280]">
|
<div className="text-xs text-[#6b7280]">
|
||||||
{isUploadingLogo ? 'Uploading...' : `Selected: ${logoFile.name}`}
|
{isUploadingLogo
|
||||||
|
? "Uploading..."
|
||||||
|
: `Selected: ${logoFile.name}`}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{(logoPreviewUrl || logoFileUrl) && (
|
{(logoPreviewUrl || logoFileUrl) && (
|
||||||
@ -463,7 +509,7 @@ const Settings = (): ReactElement => {
|
|||||||
src={logoPreviewUrl || logoFileUrl}
|
src={logoPreviewUrl || logoFileUrl}
|
||||||
alt="Logo preview"
|
alt="Logo preview"
|
||||||
className="max-w-full h-20 object-contain border border-[#d1d5db] rounded-md p-2 bg-white"
|
className="max-w-full h-20 object-contain border border-[#d1d5db] rounded-md p-2 bg-white"
|
||||||
style={{ display: 'block', maxHeight: '80px' }}
|
style={{ display: "block", maxHeight: "80px" }}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@ -496,8 +542,12 @@ const Settings = (): ReactElement => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-0.5 flex-1 min-w-0">
|
<div className="flex flex-col gap-0.5 flex-1 min-w-0">
|
||||||
<span className="text-sm font-medium text-[#0f1724]">Upload Favicon</span>
|
<span className="text-sm font-medium text-[#0f1724]">
|
||||||
<span className="text-xs font-normal text-[#9ca3af]">ICO or PNG up to 500KB.</span>
|
Upload Favicon
|
||||||
|
</span>
|
||||||
|
<span className="text-xs font-normal text-[#9ca3af]">
|
||||||
|
ICO or PNG up to 500KB.
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
id="favicon-upload"
|
id="favicon-upload"
|
||||||
@ -515,7 +565,9 @@ const Settings = (): ReactElement => {
|
|||||||
<div className="flex flex-col gap-2 mt-1">
|
<div className="flex flex-col gap-2 mt-1">
|
||||||
{faviconFile && (
|
{faviconFile && (
|
||||||
<div className="text-xs text-[#6b7280]">
|
<div className="text-xs text-[#6b7280]">
|
||||||
{isUploadingFavicon ? 'Uploading...' : `Selected: ${faviconFile.name}`}
|
{isUploadingFavicon
|
||||||
|
? "Uploading..."
|
||||||
|
: `Selected: ${faviconFile.name}`}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{(faviconPreviewUrl || faviconFileUrl) && (
|
{(faviconPreviewUrl || faviconFileUrl) && (
|
||||||
@ -525,7 +577,11 @@ const Settings = (): ReactElement => {
|
|||||||
src={faviconPreviewUrl || faviconFileUrl}
|
src={faviconPreviewUrl || faviconFileUrl}
|
||||||
alt="Favicon preview"
|
alt="Favicon preview"
|
||||||
className="w-16 h-16 object-contain border border-[#d1d5db] rounded-md p-2 bg-white"
|
className="w-16 h-16 object-contain border border-[#d1d5db] rounded-md p-2 bg-white"
|
||||||
style={{ display: 'block', width: '64px', height: '64px' }}
|
style={{
|
||||||
|
display: "block",
|
||||||
|
width: "64px",
|
||||||
|
height: "64px",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@ -544,7 +600,9 @@ const Settings = (): ReactElement => {
|
|||||||
|
|
||||||
{/* Primary Color */}
|
{/* Primary Color */}
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<label className="text-sm font-medium text-[#0f1724]">Primary Color</label>
|
<label className="text-sm font-medium text-[#0f1724]">
|
||||||
|
Primary Color
|
||||||
|
</label>
|
||||||
<div className="flex gap-3 items-center">
|
<div className="flex gap-3 items-center">
|
||||||
<div
|
<div
|
||||||
className="border border-[#d1d5db] rounded-md size-10 shrink-0"
|
className="border border-[#d1d5db] rounded-md size-10 shrink-0"
|
||||||
@ -575,7 +633,9 @@ const Settings = (): ReactElement => {
|
|||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||||
{/* Secondary Color */}
|
{/* Secondary Color */}
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<label className="text-sm font-medium text-[#0f1724]">Secondary Color</label>
|
<label className="text-sm font-medium text-[#0f1724]">
|
||||||
|
Secondary Color
|
||||||
|
</label>
|
||||||
<div className="flex gap-3 items-center">
|
<div className="flex gap-3 items-center">
|
||||||
<div
|
<div
|
||||||
className="border border-[#d1d5db] rounded-md size-10 shrink-0"
|
className="border border-[#d1d5db] rounded-md size-10 shrink-0"
|
||||||
@ -604,7 +664,9 @@ const Settings = (): ReactElement => {
|
|||||||
|
|
||||||
{/* Accent Color */}
|
{/* Accent Color */}
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<label className="text-sm font-medium text-[#0f1724]">Accent Color</label>
|
<label className="text-sm font-medium text-[#0f1724]">
|
||||||
|
Accent Color
|
||||||
|
</label>
|
||||||
<div className="flex gap-3 items-center">
|
<div className="flex gap-3 items-center">
|
||||||
<div
|
<div
|
||||||
className="border border-[#d1d5db] rounded-md size-10 shrink-0"
|
className="border border-[#d1d5db] rounded-md size-10 shrink-0"
|
||||||
@ -639,7 +701,7 @@ const Settings = (): ReactElement => {
|
|||||||
disabled={isSaving || isUploadingLogo || isUploadingFavicon}
|
disabled={isSaving || isUploadingLogo || isUploadingFavicon}
|
||||||
className="px-6 py-2.5"
|
className="px-6 py-2.5"
|
||||||
>
|
>
|
||||||
{isSaving ? 'Saving...' : 'Save Changes'}
|
{isSaving ? "Saving..." : "Save Changes"}
|
||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user