Files
ladill-transfer/resources/views/transfer/transfers/create.blade.php
T
isaaccladandCursor 9f0822d1ba
Deploy Ladill Transfer / deploy (push) Successful in 26s
Unify primary buttons with gradient pill design across the app.
Add shared btn-primary components and plus icons on create/new actions; limit overview recent transfers to three.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 22:40:41 +00:00

131 lines
9.2 KiB
PHP

<x-user-layout>
<x-slot name="title">New transfer</x-slot>
<div class="mx-auto max-w-2xl space-y-6">
<div>
<a href="{{ route('transfer.transfers.index') }}" class="text-sm text-slate-500 hover:text-slate-700"> All transfers</a>
<h1 class="mt-2 text-xl font-semibold text-slate-900">New transfer</h1>
<p class="mt-1 text-sm text-slate-500">Upload files and get a share link plus a QR code. Storage is billed monthly at GHS {{ number_format($pricePerGb, 2) }} per GB from your Ladill wallet.</p>
</div>
@if(session('error'))
<div class="rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">{{ session('error') }}</div>
@endif
<form method="post" action="{{ route('transfer.transfers.store') }}" enctype="multipart/form-data"
x-data="transferCreateForm(@js([
'initUrl' => route('transfer.transfers.upload.init'),
'chunkUrl' => route('transfer.transfers.upload.chunk'),
'finalizeUrl' => route('transfer.transfers.upload.finalize'),
'csrfToken' => csrf_token(),
]))"
@submit.prevent="submit"
class="space-y-5 rounded-2xl border border-slate-200 bg-white p-6">
@csrf
<div>
<label for="title" class="block text-sm font-medium text-slate-700">Title</label>
<input type="text" name="title" id="title" value="{{ old('title') }}" required maxlength="120"
class="mt-1 block w-full rounded-xl border-slate-200 text-sm shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
@error('title')<p class="mt-1 text-xs text-red-600">{{ $message }}</p>@enderror
</div>
<div>
<label for="message" class="block text-sm font-medium text-slate-700">Message <span class="font-normal text-slate-400">(optional)</span></label>
<textarea name="message" id="message" rows="3" maxlength="2000"
class="mt-1 block w-full rounded-xl border-slate-200 text-sm shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('message') }}</textarea>
</div>
<div>
<span class="block text-sm font-medium text-slate-700">Files</span>
<div class="mt-2 flex flex-wrap gap-2">
<button type="button"
@click="$refs.fileInput.click()"
class="inline-flex items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">
Choose files
</button>
<button type="button"
@click="$refs.folderInput.click()"
class="inline-flex items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">
Choose folder
</button>
</div>
<input type="file" x-ref="fileInput" id="files" multiple class="hidden" @change="onFilesChange">
<input type="file" x-ref="folderInput" multiple webkitdirectory class="hidden" @change="onFolderChange">
<p class="mt-1 text-xs text-slate-500">Up to {{ $maxFiles }} files. Uploads start immediately pick files or a folder anytime before creating the transfer.</p>
<div x-show="fileItems.length" x-cloak class="mt-3 space-y-2">
<template x-for="item in fileItems" :key="item.id">
<div class="rounded-xl border border-slate-200 bg-slate-50 px-3 py-2.5">
<div class="flex items-start gap-2">
<div class="min-w-0 flex-1">
<p class="truncate text-sm font-medium text-slate-800" x-text="item.name"></p>
<p class="text-xs text-slate-500" x-text="formatBytes(item.size)"></p>
</div>
<span class="shrink-0 text-xs font-medium"
:class="{
'text-indigo-600': item.status === 'uploading' || item.status === 'pending',
'text-emerald-600': item.status === 'ready',
'text-red-600': item.status === 'error',
}"
x-text="item.status === 'uploading' ? `${item.progress}%` : (item.status === 'pending' ? 'Waiting…' : (item.status === 'ready' ? 'Ready' : 'Failed'))"></span>
<button type="button"
@click="removeFileItem(item.id)"
:disabled="item.status === 'uploading'"
class="shrink-0 rounded p-0.5 text-slate-400 hover:bg-white hover:text-rose-600 disabled:opacity-40"
title="Remove">
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" d="M6 18 18 6M6 6l12 12"/></svg>
</button>
</div>
<div x-show="item.status === 'uploading'" class="mt-2">
<div class="upload-progress-track">
<div class="upload-progress-bar" :style="`width: ${item.progress}%`"></div>
</div>
</div>
<p x-show="item.status === 'error'" class="mt-1 text-xs text-red-600" x-text="item.error"></p>
</div>
</template>
<div x-show="uploading" class="rounded-xl border border-indigo-100 bg-indigo-50/70 px-3 py-2">
<div class="flex items-center justify-between gap-2 text-xs text-indigo-800">
<span class="font-medium">Uploading files…</span>
<span x-text="`${overallProgress}%`"></span>
</div>
<div class="upload-progress-track mt-2">
<div class="upload-progress-bar" :style="`width: ${overallProgress}%`"></div>
</div>
</div>
</div>
@error('files')<p class="mt-1 text-xs text-red-600">{{ $message }}</p>@enderror
@error('files.*')<p class="mt-1 text-xs text-red-600">{{ $message }}</p>@enderror
</div>
<div>
<label for="recipient_email" class="block text-sm font-medium text-slate-700">Recipient email <span class="font-normal text-slate-400">(optional)</span></label>
<input type="email" name="recipient_email" id="recipient_email" value="{{ old('recipient_email') }}" maxlength="255"
placeholder="friend@example.com"
class="mt-1 block w-full rounded-xl border-slate-200 text-sm shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
@error('recipient_email')<p class="mt-1 text-xs text-red-600">{{ $message }}</p>@enderror
<p class="mt-1 text-xs text-slate-500">A download link is emailed immediately when you create the transfer.</p>
</div>
<div class="rounded-xl border border-indigo-100 bg-indigo-50/60 px-4 py-3 text-sm text-slate-600">
<p class="font-medium text-slate-900">Monthly storage billing</p>
<p class="mt-1">GHS {{ number_format($pricePerGb, 2) }} per GB per month, debited from your wallet. Files stay available while payments succeed. If a monthly renewal fails, files are kept for {{ $gracePeriodDays }} days before deletion.</p>
</div>
<div>
<label for="password" class="block text-sm font-medium text-slate-700">Password <span class="font-normal text-slate-400">(optional)</span></label>
<input type="password" name="password" id="password" minlength="4" maxlength="64"
class="mt-1 block w-full rounded-xl border-slate-200 text-sm shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
autocomplete="new-password">
</div>
<div class="flex justify-end gap-3 pt-2">
<a href="{{ route('transfer.transfers.index') }}" class="rounded-xl border border-slate-200 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</a>
<button type="submit" class="btn-primary" :disabled="uploading || submitting">
<svg class="h-4 w-4 shrink-0" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"/></svg>
<span x-show="!uploading && !submitting">Create transfer</span>
<span x-show="uploading || submitting" x-cloak>Uploading…</span>
</button>
</div>
</form>
</div>
</x-user-layout>