153 lines
5.7 KiB
JavaScript
153 lines
5.7 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={`rounded-lg px-5 py-2.5 text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-300/75 ${disabled ? 'cursor-not-allowed bg-emerald-700/55 text-white/75' : 'bg-emerald-500 text-white hover:bg-emerald-400 shadow-[0_10px_28px_rgba(16,185,129,0.32)] ring-1 ring-emerald-200/40'}`}
|
|
>
|
|
{label}
|
|
</button>
|
|
)
|
|
}
|
|
|
|
if (step === 2) {
|
|
const disabled = !canContinue
|
|
return (
|
|
<button
|
|
type="button"
|
|
disabled={disabled}
|
|
title={disabled ? disableReason : 'Continue to Publish'}
|
|
onClick={() => onContinue?.()}
|
|
className={`rounded-lg px-4 py-2 text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-300/75 ${disabled ? 'cursor-not-allowed bg-sky-700/45 text-sky-100/75' : 'bg-sky-400 text-slate-950 hover:bg-sky-300 shadow-[0_10px_28px_rgba(56,189,248,0.28)] ring-1 ring-sky-100/45'}`}
|
|
>
|
|
Continue to Publish
|
|
</button>
|
|
)
|
|
}
|
|
|
|
const disabled = !canPublish || isPublishing
|
|
return (
|
|
<button
|
|
type="button"
|
|
disabled={disabled}
|
|
title={disabled ? disableReason : 'Publish artwork'}
|
|
onClick={() => onPublish?.()}
|
|
className={`rounded-lg px-4 py-2 text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-300/75 ${disabled ? 'cursor-not-allowed bg-emerald-700/45 text-emerald-100/75' : 'bg-emerald-400 text-slate-950 shadow-[0_0_0_1px_rgba(167,243,208,0.85),0_0_24px_rgba(52,211,153,0.45)] hover:bg-emerald-300'}`}
|
|
>
|
|
{isPublishing ? 'Publishing…' : 'Publish'}
|
|
</button>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<footer data-testid="wizard-action-bar" className={`${mobileSticky ? 'sticky bottom-0 z-20' : ''} rounded-xl border border-white/10 bg-slate-950/80 p-3 shadow-[0_-12px_32px_rgba(2,8,23,0.65)] backdrop-blur sm:p-4 lg:static lg:shadow-none`}>
|
|
<div className="flex flex-wrap items-center justify-end gap-2.5">
|
|
{canGoBack && (
|
|
<button
|
|
type="button"
|
|
onClick={() => onBack?.()}
|
|
className="rounded-lg border border-white/30 bg-white/10 px-3.5 py-2 text-sm font-medium text-white transition hover:bg-white/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70"
|
|
>
|
|
Back
|
|
</button>
|
|
)}
|
|
|
|
{showSaveDraft && (
|
|
<button
|
|
type="button"
|
|
onClick={() => onSaveDraft?.()}
|
|
className="rounded-lg border border-purple-300/45 bg-purple-500/20 px-3.5 py-2 text-sm font-medium text-purple-50 transition hover:bg-purple-500/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-purple-300/70"
|
|
>
|
|
Save draft
|
|
</button>
|
|
)}
|
|
|
|
{step === 1 && canCancel && (
|
|
<button
|
|
type="button"
|
|
onClick={handleCancel}
|
|
disabled={isCancelling}
|
|
title={confirmCancel ? 'Click again to confirm cancel' : 'Cancel current upload'}
|
|
className="rounded-lg border border-amber-300/45 bg-amber-500/20 px-3.5 py-2 text-sm font-medium text-amber-50 transition hover:bg-amber-500/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-300/75 disabled:cursor-not-allowed disabled:opacity-60"
|
|
>
|
|
{isCancelling ? 'Cancelling…' : confirmCancel ? 'Cancel upload?' : 'Cancel'}
|
|
</button>
|
|
)}
|
|
|
|
{canRetry && (
|
|
<button
|
|
type="button"
|
|
onClick={() => onRetry?.()}
|
|
className="rounded-lg border border-amber-300/45 bg-amber-500/20 px-3.5 py-2 text-sm font-medium text-amber-50 transition hover:bg-amber-500/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-300/75"
|
|
>
|
|
Retry
|
|
</button>
|
|
)}
|
|
|
|
{canReset && (
|
|
<button
|
|
type="button"
|
|
onClick={() => onReset?.()}
|
|
className="rounded-lg border border-white/30 bg-white/10 px-3.5 py-2 text-sm font-medium text-white transition hover:bg-white/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70"
|
|
>
|
|
{resetLabel}
|
|
</button>
|
|
)}
|
|
|
|
{renderPrimary()}
|
|
</div>
|
|
</footer>
|
|
)
|
|
}
|