import { ChangeEvent, FormEvent, useMemo, useRef, useState } from 'react'; import { IoCloudUploadOutline } from 'react-icons/io5'; import { uploadCustomView } from '../../../../common/api/customViews'; import { maybeAxiosError } from '../../../../common/api/utils'; import Button from '../../../../common/components/buttons/Button'; import Input from '../../../../common/components/input/input/Input'; import * as Panel from '../../panel-utils/PanelUtils'; import { getFileError, getSlugError, getViewUrl, maxUploadLabel } from './customViews.utils'; import style from './CustomViews.module.scss'; interface CustomViewFormProps { onComplete: () => void; onClose: () => void; } export default function CustomViewForm({ onComplete, onClose }: CustomViewFormProps) { const [slug, setSlug] = useState(''); const [selectedFile, setSelectedFile] = useState(null); const [slugDirty, setSlugDirty] = useState(false); const [fileDirty, setFileDirty] = useState(false); const [isUploading, setIsUploading] = useState(false); const [error, setError] = useState(null); const fileInputRef = useRef(null); const normalisedSlug = useMemo(() => slug.trim().toLowerCase(), [slug]); const previewUrl = getViewUrl(normalisedSlug); const slugError = useMemo(() => getSlugError(normalisedSlug), [normalisedSlug]); const fileError = useMemo(() => getFileError(selectedFile), [selectedFile]); const canUpload = Boolean(normalisedSlug && selectedFile) && !slugError && !fileError && !isUploading; const handleSelectFile = (event: ChangeEvent) => { setSelectedFile(event.target.files?.[0] ?? null); setFileDirty(true); setError(null); }; const handleUpload = async (event: FormEvent) => { event.preventDefault(); if (!selectedFile || slugError || fileError) return; try { setIsUploading(true); setError(null); await uploadCustomView(normalisedSlug, selectedFile); onComplete(); } catch (err) { setError(maybeAxiosError(err)); } finally { setIsUploading(false); } }; return (
1. Choose a name
Name { setSlug(event.target.value); setSlugDirty(true); }} placeholder='my-view' aria-label='Custom view name' autoCapitalize='off' autoComplete='off' fluid /> Use lowercase letters, numbers, and dashes. Example: my-view Preview URL: {previewUrl} {slugDirty && slugError && {slugError}}
2. Select index.html
Upload file {selectedFile ? `${selectedFile.name} (${Math.ceil(selectedFile.size / 1024)} KB)` : 'No file selected'} Accepted: index.html only, maximum {maxUploadLabel}. {fileDirty && fileError && {fileError}}
{error && {error}}
); }