Remove Amazon filament price tracking
Deploy HickLab3D Dashboard / Deploy to production (push) Successful in 2m41s
Deploy HickLab3D Dashboard / Deploy to production (push) Successful in 2m41s
This commit is contained in:
+3
-3
@@ -41,15 +41,15 @@ if (document.querySelector('[data-dashboard-chart]')) {
|
||||
markers: { size: 3 },
|
||||
legend: { show: false },
|
||||
};
|
||||
} else if (element.dataset.dashboardChart === 'materials') {
|
||||
} else if (element.dataset.dashboardChart === 'printers') {
|
||||
options = {
|
||||
...chartBase,
|
||||
chart: { ...chartBase.chart, type: 'donut', height },
|
||||
labels: data.map((item) => item.label),
|
||||
series: data.map((item) => item.count),
|
||||
colors: ['#e3f504', '#7dd3a3', '#8b9df0', '#f0a46b', '#cc9df0', '#66cbd1', '#f17fa5'],
|
||||
colors: ['#e3f504', '#7dd3a3', '#f0a46b', '#f17fa5', '#8b9df0'],
|
||||
legend: { position: 'bottom', fontSize: '12px', labels: { colors: '#b8bec4' } },
|
||||
plotOptions: { pie: { donut: { size: '68%', labels: { show: true, total: { show: true, label: 'Spools' } } } } },
|
||||
plotOptions: { pie: { donut: { size: '68%', labels: { show: true, total: { show: true, label: 'Printers' } } } } },
|
||||
dataLabels: { enabled: false },
|
||||
stroke: { colors: ['#17191b'], width: 2 },
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<p class="rounded-full border border-slate-700 px-3 py-1.5 text-xs text-slate-400">Updated when you open this page</p>
|
||||
</div>
|
||||
|
||||
<section class="grid gap-4 sm:grid-cols-2 xl:grid-cols-4" aria-label="Key metrics">
|
||||
<section @class(['grid gap-4 sm:grid-cols-2', 'xl:grid-cols-4' => $isAdmin]) aria-label="Key metrics">
|
||||
@if($isAdmin)
|
||||
<a href="{{ route('etsy.index') }}" class="group rounded-2xl border border-slate-800 bg-slate-900 p-5 transition hover:border-brand/50">
|
||||
<div class="flex items-center justify-between"><p class="text-sm font-medium text-slate-400">Awaiting dispatch</p><span class="text-brand">↗</span></div>
|
||||
@@ -23,24 +23,18 @@
|
||||
<p class="mt-4 text-3xl font-bold tabular-nums">{{ $printerStatus === 'Live from BamBuddy' ? $printingCount : '—' }}<span class="ml-2 text-base font-medium text-slate-500">/ {{ $printerStatus === 'Live from BamBuddy' ? count($printers) : '—' }}</span></p>
|
||||
<p class="mt-2 text-xs text-slate-500">{{ $printerStatus }}</p>
|
||||
</a>
|
||||
<a href="{{ route('filaments.index') }}" class="group rounded-2xl border border-slate-800 bg-slate-900 p-5 transition hover:border-brand/50">
|
||||
<div class="flex items-center justify-between"><p class="text-sm font-medium text-slate-400">Tracked materials</p><span class="text-brand">↗</span></div>
|
||||
<p class="mt-4 text-3xl font-bold tabular-nums">{{ $filamentCount }}</p>
|
||||
<p class="mt-2 text-xs text-slate-500">{{ count($materials) }} material types in your tracker</p>
|
||||
</a>
|
||||
@if($isAdmin)
|
||||
<a href="{{ route('etsy.index') }}" class="group rounded-2xl border border-slate-800 bg-slate-900 p-5 transition hover:border-brand/50">
|
||||
<div class="flex items-center justify-between"><p class="text-sm font-medium text-slate-400">Active listings</p><span class="text-brand">↗</span></div>
|
||||
<p class="mt-4 text-3xl font-bold tabular-nums">{{ $listingCount ?? '—' }}</p>
|
||||
<p class="mt-2 text-xs text-slate-500">{{ $etsyStatus }}</p>
|
||||
</a>
|
||||
@else
|
||||
@endif
|
||||
<a href="{{ route('dryer') }}" class="group rounded-2xl border border-slate-800 bg-slate-900 p-5 transition hover:border-brand/50">
|
||||
<div class="flex items-center justify-between"><p class="text-sm font-medium text-slate-400">Filament dryer</p><span class="text-brand">↗</span></div>
|
||||
<p class="mt-4 text-2xl font-bold">{{ $dryerState }}</p>
|
||||
<p class="mt-2 text-xs text-slate-500">Current workshop state</p>
|
||||
</a>
|
||||
@endif
|
||||
</section>
|
||||
|
||||
<div class="grid gap-4 xl:grid-cols-3">
|
||||
@@ -58,11 +52,11 @@
|
||||
</section>
|
||||
@endif
|
||||
<section class="min-w-0 rounded-2xl border border-slate-800 bg-slate-900 {{ $isAdmin ? '' : 'xl:col-span-2' }}">
|
||||
<div class="border-b border-slate-800 px-5 py-5 sm:px-6"><h3 class="font-semibold">Material mix</h3><p class="mt-1 text-xs text-slate-400">Tracked filaments by material</p></div>
|
||||
@if($filamentCount)
|
||||
<div class="p-5 sm:p-6"><div class="h-64 w-full" data-dashboard-chart="materials" data-chart="{{ json_encode($materials) }}" role="img" aria-label="Tracked filaments by material"></div></div>
|
||||
<div class="border-b border-slate-800 px-5 py-5 sm:px-6"><h3 class="font-semibold">Print farm status</h3><p class="mt-1 text-xs text-slate-400">Live printer states from BamBuddy</p></div>
|
||||
@if(count($printerChart))
|
||||
<div class="p-5 sm:p-6"><div class="h-64 w-full" data-dashboard-chart="printers" data-chart="{{ json_encode($printerChart) }}" role="img" aria-label="Printers by current state"></div></div>
|
||||
@else
|
||||
<div class="flex min-h-64 flex-col items-center justify-center gap-2 px-6 text-center"><p class="font-medium">No materials tracked yet</p><a href="{{ route('filaments.index') }}" class="text-sm text-brand hover:underline">Open filament tracker →</a></div>
|
||||
<div class="flex min-h-64 flex-col items-center justify-center gap-2 px-6 text-center"><p class="font-medium">No printer status to chart</p><a href="{{ route('printers.index') }}" class="text-sm text-brand hover:underline">Open print farm →</a></div>
|
||||
@endif
|
||||
</section>
|
||||
@unless($isAdmin)
|
||||
@@ -96,8 +90,8 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="grid gap-4 xl:grid-cols-2">
|
||||
@if($isAdmin)
|
||||
@if($isAdmin)
|
||||
<div>
|
||||
<section class="rounded-2xl border border-slate-800 bg-slate-900">
|
||||
<div class="flex items-center justify-between gap-3 border-b border-slate-800 px-5 py-4 sm:px-6"><div><h3 class="font-semibold">Recent shipments</h3><p class="mt-1 text-xs text-slate-400">Parcel2Go · {{ $shippingStatus }}</p></div><a href="{{ route('shipping') }}" class="text-sm font-semibold text-brand hover:underline">Labels & collections →</a></div>
|
||||
<div class="divide-y divide-slate-800 px-5 sm:px-6">
|
||||
@@ -106,16 +100,7 @@
|
||||
@empty<p class="py-8 text-sm text-slate-400">{{ $shippingStatus === 'Live account' ? 'No recent shipments.' : $shippingStatus }}</p>@endforelse
|
||||
</div>
|
||||
</section>
|
||||
@endif
|
||||
<section class="rounded-2xl border border-slate-800 bg-slate-900">
|
||||
<div class="flex items-center justify-between gap-3 border-b border-slate-800 px-5 py-4 sm:px-6"><div><h3 class="font-semibold">Filament tracker</h3><p class="mt-1 text-xs text-slate-400">Most recently tracked materials</p></div><a href="{{ route('filaments.index') }}" class="text-sm font-semibold text-brand hover:underline">View all →</a></div>
|
||||
<div class="divide-y divide-slate-800 px-5 sm:px-6">
|
||||
@forelse($recentFilaments as $filament)
|
||||
<div class="flex items-center justify-between gap-4 py-4"><div class="min-w-0"><p class="truncate font-medium">{{ $filament->filamentName }}</p><p class="mt-1 text-xs text-slate-400">{{ $filament->brand ?: 'Unknown brand' }} · {{ $filament->material ?: 'Material pending' }}</p></div><span class="shrink-0 font-semibold tabular-nums">{{ $filament->prices->first() ? '£'.number_format($filament->prices->first()->price, 2) : 'Pending' }}</span></div>
|
||||
@empty<p class="py-8 text-sm text-slate-400">No filament is being tracked yet.</p>@endforelse
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<section class="flex flex-wrap items-center justify-between gap-4 rounded-2xl border border-slate-800 bg-slate-900 px-5 py-4 sm:px-6"><div><h3 class="font-semibold">Dryer status</h3><p class="mt-1 text-sm text-slate-400">{{ $dryerState }}</p></div><a href="{{ route('dryer') }}" class="text-sm font-semibold text-brand hover:underline">Open controls →</a></section>
|
||||
@endsection
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
@section('title', 'Track filament')
|
||||
@section('content')
|
||||
<form method="post" action="{{ route('filaments.store') }}" class="grid max-w-2xl gap-5 rounded-2xl border border-slate-800 bg-slate-900 p-6">@csrf
|
||||
@foreach([['filamentName','Filament name','e.g. PLA Matte Black'],['amazonUrl','Product URL','https://www.amazon.co.uk/...'],['brand','Brand','Optional'],['material','Material','PLA, PETG, ABS…'],['color','Colour','Optional'],['filamentWeight','Weight (g)','1000'],['itemDiameter','Diameter (mm)','1.75']] as [$name,$label,$placeholder])
|
||||
<label class="grid gap-2 text-sm font-medium">{{ $label }}<input name="{{ $name }}" type="{{ $name === 'amazonUrl' ? 'url' : (in_array($name, ['filamentWeight','itemDiameter']) ? 'number' : 'text') }}" @if(in_array($name, ['filamentWeight','itemDiameter'])) step="0.01" @endif value="{{ old($name) }}" placeholder="{{ $placeholder }}" @if(in_array($name, ['filamentName','amazonUrl'])) required @endif class="rounded-xl border border-slate-700 bg-slate-950 px-4 py-3 outline-none focus:border-brand"></label>
|
||||
@endforeach
|
||||
<div class="flex gap-3"><button class="rounded-xl bg-brand px-5 py-3 font-semibold text-slate-950">Start tracking</button><a href="{{ route('filaments.index') }}" class="rounded-xl border border-slate-700 px-5 py-3">Cancel</a></div>
|
||||
</form>
|
||||
@endsection
|
||||
@@ -1,10 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
@section('title', 'Filament tracker')
|
||||
@section('content')
|
||||
<div class="flex flex-wrap items-end justify-between gap-4"><div><h2 class="text-2xl font-bold">Filament prices</h2><p class="mt-1 text-slate-400">Recent prices and offers from tracked listings.</p></div>@if(auth()->user()->role === 'admin')<a href="{{ route('filaments.create') }}" class="rounded-xl bg-brand px-4 py-3 text-sm font-semibold text-slate-950">Track filament</a>@endif</div>
|
||||
<div class="overflow-x-auto rounded-2xl border border-slate-800 bg-slate-900"><table class="w-full min-w-[700px] text-left text-sm"><thead class="border-b border-slate-800 text-xs uppercase tracking-widest text-slate-500"><tr><th class="p-5">Filament</th><th class="p-5">Material</th><th class="p-5">Latest price</th><th class="p-5">Discount</th><th class="p-5">Updated</th><th class="p-5"></th></tr></thead><tbody class="divide-y divide-slate-800">@forelse($filaments as $filament)
|
||||
@php $latest = $filament->prices->first(); $discount = $latest?->currentDiscount['discount']['value'] ?? 0; @endphp
|
||||
<tr><td class="p-5"><a href="{{ $filament->amazonUrl }}" target="_blank" rel="noopener noreferrer" class="font-semibold text-brand hover:underline">{{ $filament->filamentName }} ↗</a><p class="mt-1 text-slate-400">{{ $filament->brand ?: 'Unknown brand' }} · {{ $filament->color ?: 'Colour unknown' }}</p></td><td class="p-5">{{ $filament->material ?: '—' }}</td><td class="p-5 font-semibold">{{ $latest ? '£'.number_format($latest->price, 2) : 'Pending' }}</td><td class="p-5">{{ $discount ? $discount.'%' : '—' }}</td><td class="p-5 text-slate-400">{{ $latest?->recordedAt?->diffForHumans() ?? '—' }}</td><td class="p-5">@if(auth()->user()->role === 'admin')<form method="post" action="{{ route('filaments.destroy', $filament) }}" onsubmit="return confirm('Stop tracking this filament?')">@csrf @method('DELETE')<button class="text-rose-400">Remove</button></form>@endif</td></tr>
|
||||
@empty<tr><td colspan="6" class="p-8 text-center text-slate-400">No filament is being tracked yet.</td></tr>@endforelse</tbody></table></div>
|
||||
{{ $filaments->links() }}
|
||||
@endsection
|
||||
@@ -20,7 +20,7 @@
|
||||
<div><strong class="block text-lg tracking-tight">HickLab3D</strong><span class="text-xs text-slate-400">Operations studio</span></div>
|
||||
</div>
|
||||
<nav class="flex gap-1 overflow-x-auto px-4 pb-4 lg:flex-col lg:overflow-visible" aria-label="Main navigation">
|
||||
@php $links = [['dashboard', 'Overview'], ['printers.index', 'Print farm'], ['etsy.index', 'Etsy'], ['filaments.index', 'Filament'], ['shipping', 'Shipping'], ['dryer', 'Dryer']]; @endphp
|
||||
@php $links = [['dashboard', 'Overview'], ['printers.index', 'Print farm'], ['etsy.index', 'Etsy'], ['shipping', 'Shipping'], ['dryer', 'Dryer']]; @endphp
|
||||
@foreach($links as [$routeName, $label])
|
||||
@if(! in_array($routeName, ['shipping', 'etsy.index']) || auth()->user()->role === 'admin')
|
||||
<a href="{{ route($routeName) }}" @class(['shrink-0 rounded-xl px-4 py-3 text-sm font-medium transition-colors hover:bg-slate-800 hover:text-white', 'bg-brand/10 text-brand' => request()->routeIs($routeName) || request()->routeIs(str_replace('.index', '.*', $routeName)), 'text-slate-400' => !request()->routeIs($routeName)])>{{ $label }}</a>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<input name="email" type="email" placeholder="Email address" required class="rounded-xl border border-slate-700 bg-slate-950 px-4 py-3">
|
||||
<input name="password" type="password" minlength="12" placeholder="Password (12+ characters)" required class="rounded-xl border border-slate-700 bg-slate-950 px-4 py-3">
|
||||
<select name="role" class="rounded-xl border border-slate-700 bg-slate-950 px-4 py-3"><option value="user">User</option><option value="admin">Admin</option></select>
|
||||
<label class="flex items-center gap-2 text-sm text-slate-300"><input type="checkbox" name="alertEmails" value="1"> Send price alerts</label>
|
||||
<div><button class="rounded-xl bg-brand px-5 py-3 font-semibold text-slate-950">Create user</button></div>
|
||||
</form>
|
||||
<div class="grid gap-3">@foreach($users as $user)
|
||||
@@ -25,7 +24,6 @@
|
||||
<label class="grid gap-1 text-sm text-slate-400">Email<input name="email" type="email" value="{{ $user->email }}" required class="rounded-lg border border-slate-700 bg-slate-950 px-3 py-2 text-slate-100"></label>
|
||||
<label class="grid gap-1 text-sm text-slate-400">Role<select name="role" class="rounded-lg border border-slate-700 bg-slate-950 px-3 py-2 text-slate-100"><option value="user" @selected($user->role === 'user')>User</option><option value="admin" @selected($user->role === 'admin')>Admin</option></select></label>
|
||||
<label class="grid gap-1 text-sm text-slate-400">New password (leave blank to keep current)<input name="password" type="password" minlength="12" class="rounded-lg border border-slate-700 bg-slate-950 px-3 py-2 text-slate-100"></label>
|
||||
<div class="flex items-end"><input type="hidden" name="alertEmails" value="0"><label class="flex items-center gap-2 text-sm text-slate-300"><input type="checkbox" name="alertEmails" value="1" @checked($user->alertEmails)> Send price alerts</label></div>
|
||||
<div class="md:col-span-2"><button class="rounded-lg bg-brand px-4 py-2 text-sm font-semibold text-slate-950">Save changes</button></div>
|
||||
</form>
|
||||
</details>
|
||||
|
||||
Reference in New Issue
Block a user