Files
SkinbaseNova/resources/js/components/upload/UploadActions.jsx
Gregor Klevze 979e011257 Refactor dashboard and upload flows
Remove dead admin UI code, redesign dashboard followers/following and upload experiences, and add schema audit tooling with repair migrations for forum and upload drift.
2026-03-21 11:02:22 +01:00

160 lines
4.4 KiB
JavaScript

import React, { useEffect, useState } from 'react'
export default function UploadActions({
step = 1,
canStart = false,
canContinue = false,
canPublish = false,
canGoBack = false,
canReset = true,
canCancel = false,
canRetry = false,
isUploading = false,
isProcessing = false,
isPublishing = false,
isCancelling = false,
disableReason = 'Complete required fields',
onStart,
onContinue,
onPublish,
onBack,
onCancel,
onReset,
onRetry,
onSaveDraft,
showSaveDraft = false,
mobileSticky = true,
resetLabel = 'Reset',
}) {
const [confirmCancel, setConfirmCancel] = useState(false)
useEffect(() => {
if (!confirmCancel) return
const timer = window.setTimeout(() => setConfirmCancel(false), 3200)
return () => window.clearTimeout(timer)
}, [confirmCancel])
const handleCancel = () => {
if (!canCancel || isCancelling) return
if (!confirmCancel) {
setConfirmCancel(true)
return
}
setConfirmCancel(false)
onCancel?.()
}
const renderPrimary = () => {
if (step === 1) {
const disabled = !canStart || isUploading || isProcessing || isCancelling
const label = isUploading ? 'Uploading…' : isProcessing ? 'Processing…' : 'Start upload'
return (
<button
type="button"
disabled={disabled}
title={disabled ? disableReason : 'Start upload'}
onClick={() => onStart?.()}
className={`btn-primary text-sm ${disabled ? 'cursor-not-allowed opacity-60' : ''}`}
>
{label}
</button>
)
}
if (step === 2) {
const disabled = !canContinue
return (
<button
type="button"
disabled={disabled}
title={disabled ? disableReason : 'Continue to Publish'}
onClick={() => onContinue?.()}
className={`btn-primary text-sm ${disabled ? 'cursor-not-allowed opacity-60' : ''}`}
>
Continue to Publish
</button>
)
}
const disabled = !canPublish || isPublishing
return (
<button
type="button"
disabled={disabled}
title={disabled ? disableReason : 'Publish artwork'}
onClick={() => onPublish?.()}
className={`btn-primary text-sm ${disabled ? 'cursor-not-allowed opacity-60' : ''}`}
>
{isPublishing ? 'Publishing…' : 'Publish'}
</button>
)
}
return (
<footer data-testid="wizard-action-bar" className={`${mobileSticky ? 'sticky bottom-0 z-20 px-4 pb-3 lg:static lg:px-0 lg:pb-0' : ''}`}>
<div className="mx-auto w-full max-w-4xl rounded-[24px] border border-white/10 bg-[#08111c]/88 p-3 shadow-[0_-12px_32px_rgba(2,8,23,0.65)] backdrop-blur-sm sm:p-4 lg:shadow-none">
<div className="flex flex-wrap items-center justify-between gap-3">
<div className="text-xs uppercase tracking-[0.18em] text-white/35">
{step === 1 ? 'Step 1 of 3' : step === 2 ? 'Step 2 of 3' : 'Step 3 of 3'}
</div>
<div className="flex flex-wrap items-center justify-end gap-2.5">
{canGoBack && (
<button
type="button"
onClick={() => onBack?.()}
className="btn-secondary text-sm"
>
Back
</button>
)}
{showSaveDraft && (
<button
type="button"
onClick={() => onSaveDraft?.()}
className="btn-secondary text-sm"
>
Save draft
</button>
)}
{step === 1 && canCancel && (
<button
type="button"
onClick={handleCancel}
disabled={isCancelling}
title={confirmCancel ? 'Click again to confirm cancel' : 'Cancel current upload'}
className="btn-secondary text-sm disabled:cursor-not-allowed disabled:opacity-60"
>
{isCancelling ? 'Cancelling…' : confirmCancel ? 'Cancel upload?' : 'Cancel'}
</button>
)}
{canRetry && (
<button
type="button"
onClick={() => onRetry?.()}
className="btn-secondary text-sm"
>
Retry
</button>
)}
{canReset && (
<button
type="button"
onClick={() => onReset?.()}
className="btn-secondary text-sm"
>
{resetLabel}
</button>
)}
{renderPrimary()}
</div>
</div>
</div>
</footer>
)
}