Deploy Ladill Transfer / deploy (push) Successful in 44s
Recipients can be emailed the download link immediately and at optional reminders (7/3/1 days before unavailable, or when grace period starts). Co-authored-by: Cursor <cursoragent@cursor.com>
98 lines
6.7 KiB
PHP
98 lines
6.7 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 + QR code. Storage is billed monthly from your Ladill wallet while the transfer stays active.</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>
|
|
<label for="files" class="block text-sm font-medium text-slate-700">Files</label>
|
|
<input type="file" id="files" multiple required @change="onFilesChange"
|
|
class="mt-1 block w-full text-sm text-slate-600 file:mr-4 file:rounded-lg file:border-0 file:bg-indigo-50 file:px-4 file:py-2 file:text-sm file:font-semibold file:text-indigo-700 hover:file:bg-indigo-100">
|
|
<p class="mt-1 text-xs text-slate-500">Up to {{ $maxFiles }} files. Large files upload in small chunks — no practical size limit.</p>
|
|
<template x-if="uploading">
|
|
<div class="mt-2">
|
|
<div class="h-2 w-full overflow-hidden rounded-full bg-slate-100">
|
|
<div class="h-full rounded-full bg-indigo-600 transition-all" :style="`width: ${uploadProgress}%`"></div>
|
|
</div>
|
|
<p class="mt-1 text-xs text-slate-500" x-text="uploadLabel"></p>
|
|
</div>
|
|
</template>
|
|
@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-2 text-xs font-medium text-slate-600">Email milestones</p>
|
|
<div class="mt-2 space-y-2">
|
|
@foreach($emailMilestones as $id => $label)
|
|
<label class="flex items-start gap-2 text-sm text-slate-600">
|
|
<input type="checkbox" name="email_milestones[]" value="{{ $id }}"
|
|
@checked(in_array($id, old('email_milestones', $defaultEmailMilestones), true))
|
|
class="mt-0.5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500">
|
|
<span>{{ $label }}</span>
|
|
</label>
|
|
@endforeach
|
|
</div>
|
|
@error('email_milestones')<p class="mt-1 text-xs text-red-600">{{ $message }}</p>@enderror
|
|
@error('email_milestones.*')<p class="mt-1 text-xs text-red-600">{{ $message }}</p>@enderror
|
|
</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="rounded-xl bg-indigo-600 px-4 py-2 text-sm font-semibold text-white hover:bg-indigo-700 disabled:opacity-60"
|
|
:disabled="uploading || submitting">
|
|
<span x-show="!uploading && !submitting">Create transfer</span>
|
|
<span x-show="uploading || submitting" x-cloak>Uploading…</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</x-user-layout>
|