619 lines
38 KiB
PHP
619 lines
38 KiB
PHP
@extends('layouts.admin')
|
|
|
|
@section('title', 'MakerWorld Collecties & Auto-Sync | Jouwdriedee.nl Beheer')
|
|
|
|
@section('content')
|
|
<div class="space-y-6" x-data="makerWorldSyncApp()">
|
|
|
|
<!-- Header -->
|
|
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4 pb-6 border-b border-slate-200/80">
|
|
<div>
|
|
<div class="inline-flex items-center space-x-2 text-xs font-semibold text-slate-500 mb-1">
|
|
<span class="inline-block w-2 h-2 rounded-full bg-emerald-500 animate-pulse"></span>
|
|
<span>MakerWorld Sync Engine</span>
|
|
<span class="text-slate-300">•</span>
|
|
<span>10-minuten automatische synchronisatie</span>
|
|
</div>
|
|
<h1 class="text-2xl font-bold tracking-tight text-slate-900">MakerWorld Product Importer & Collecties</h1>
|
|
<p class="text-xs text-slate-500 mt-1">
|
|
Koppel MakerWorld collecties van je profiel (<code class="text-slate-800 font-mono bg-slate-100 px-1.5 py-0.5 rounded">@user_1718037659</code>). Nieuwe prints worden elke 10 minuten automatisch binnengehaald.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="flex items-center space-x-2">
|
|
<a href="{{ route('admin.makerworld.staging') }}" class="inline-flex items-center space-x-2 px-3.5 py-2 rounded-xl bg-slate-900 text-white text-xs font-medium hover:bg-slate-800 transition shadow-xs">
|
|
<i data-lucide="layers" class="w-4 h-4"></i>
|
|
<span>Artikel Beheer</span>
|
|
@if($stagedCount > 0)
|
|
<span class="px-1.5 py-0.5 rounded-md bg-white/20 text-white text-[10px] font-bold">
|
|
{{ $stagedCount }}
|
|
</span>
|
|
@endif
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Notification Alerts -->
|
|
@if(session('success'))
|
|
<div class="p-3.5 rounded-xl bg-emerald-50 border border-emerald-200/60 text-emerald-800 text-xs flex items-center space-x-2.5">
|
|
<i data-lucide="check-circle" class="w-4 h-4 text-emerald-600 shrink-0"></i>
|
|
<span class="font-medium">{{ session('success') }}</span>
|
|
</div>
|
|
@endif
|
|
|
|
@if(session('warning'))
|
|
<div class="p-3.5 rounded-xl bg-amber-50 border border-amber-200/60 text-amber-800 text-xs flex items-center space-x-2.5">
|
|
<i data-lucide="alert-triangle" class="w-4 h-4 text-amber-600 shrink-0"></i>
|
|
<span class="font-medium">{{ session('warning') }}</span>
|
|
</div>
|
|
@endif
|
|
|
|
@if(session('error'))
|
|
<div class="p-3.5 rounded-xl bg-rose-50 border border-rose-200/60 text-rose-800 text-xs flex items-center space-x-2.5">
|
|
<i data-lucide="x-circle" class="w-4 h-4 text-rose-600 shrink-0"></i>
|
|
<span class="font-medium">{{ session('error') }}</span>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- 2FA Verificatiecode Invoerscherm (Bambu Lab) -->
|
|
@if(session('makerworld_2fa_account'))
|
|
<div class="bg-white p-6 sm:p-8 rounded-2xl border border-slate-200/80 shadow-xs">
|
|
<div class="max-w-md mx-auto text-center space-y-4">
|
|
<div class="w-12 h-12 rounded-xl bg-slate-100 text-slate-700 flex items-center justify-center mx-auto">
|
|
<i data-lucide="shield-check" class="w-6 h-6"></i>
|
|
</div>
|
|
<div>
|
|
<span class="px-2.5 py-0.5 rounded-full text-[11px] font-semibold bg-slate-100 text-slate-700">
|
|
Tweestapsverificatie (2FA)
|
|
</span>
|
|
<h2 class="text-xl font-bold text-slate-900 mt-2">Bambu Lab Beveiligingscode</h2>
|
|
<p class="text-xs text-slate-500 mt-1">
|
|
Vul de 6-cijferige verificatiecode in die verzonden is naar <strong class="text-slate-800 font-mono">{{ session('makerworld_2fa_account') }}</strong>.
|
|
</p>
|
|
</div>
|
|
|
|
<form action="{{ route('admin.makerworld.verify-code') }}" method="POST" class="mt-4 space-y-4">
|
|
@csrf
|
|
<input type="hidden" name="account" value="{{ session('makerworld_2fa_account') }}">
|
|
|
|
<div class="flex justify-center">
|
|
<input
|
|
type="text"
|
|
name="code"
|
|
maxlength="6"
|
|
placeholder="123456"
|
|
autofocus
|
|
required
|
|
class="w-48 text-center text-2xl font-mono font-bold tracking-widest px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl text-slate-900 focus:bg-white focus:outline-none focus:ring-2 focus:ring-slate-900/10 focus:border-slate-900 placeholder-slate-400"
|
|
>
|
|
</div>
|
|
|
|
<div class="flex items-center justify-center space-x-3 pt-2">
|
|
<button type="submit" class="px-6 py-2.5 bg-slate-900 hover:bg-slate-800 text-white font-medium rounded-xl text-xs transition flex items-center space-x-2 shadow-xs">
|
|
<i data-lucide="check" class="w-4 h-4"></i>
|
|
<span>Verifieer & Koppel</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="pt-3 border-t border-slate-100 flex items-center justify-center space-x-4 text-xs text-slate-500">
|
|
<form action="{{ route('admin.makerworld.resend-code') }}" method="POST">
|
|
@csrf
|
|
<input type="hidden" name="account" value="{{ session('makerworld_2fa_account') }}">
|
|
<button type="submit" class="hover:text-slate-900 underline font-medium transition">
|
|
Code opnieuw verzenden
|
|
</button>
|
|
</form>
|
|
<span>•</span>
|
|
<a href="{{ route('admin.makerworld.index', ['tab' => 'auth']) }}" class="hover:text-slate-900 underline font-medium transition">
|
|
Ander account
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- TAB Bar: Subtle Segmented Control -->
|
|
<div class="flex items-center space-x-1.5 p-1 bg-slate-100/80 rounded-xl max-w-max text-xs font-medium">
|
|
<a href="{{ route('admin.makerworld.index', ['tab' => 'collections']) }}" class="px-3 py-1.5 rounded-lg transition flex items-center space-x-1.5 {{ $currentTab === 'collections' ? 'bg-white text-slate-900 font-semibold shadow-2xs' : 'text-slate-600 hover:text-slate-900' }}">
|
|
<i data-lucide="folder-sync" class="w-3.5 h-3.5"></i>
|
|
<span>Gekoppelde Collecties</span>
|
|
<span class="px-1.5 py-0.2 rounded-md text-[10px] {{ $currentTab === 'collections' ? 'bg-slate-100 text-slate-700' : 'bg-slate-200/60 text-slate-600' }}">
|
|
{{ $trackedCollections->count() }}
|
|
</span>
|
|
</a>
|
|
|
|
<a href="{{ route('admin.makerworld.staging') }}" class="px-3 py-1.5 rounded-lg transition flex items-center space-x-1.5 text-slate-600 hover:text-slate-900">
|
|
<i data-lucide="layers" class="w-3.5 h-3.5"></i>
|
|
<span>Artikel Beheer</span>
|
|
@if($stagedCount > 0)
|
|
<span class="px-1.5 py-0.2 rounded-md text-[10px] bg-slate-900 text-white font-semibold">
|
|
{{ $stagedCount }}
|
|
</span>
|
|
@endif
|
|
</a>
|
|
|
|
<a href="{{ route('admin.makerworld.index', ['tab' => 'quick']) }}" class="px-3 py-1.5 rounded-lg transition flex items-center space-x-1.5 {{ $currentTab === 'quick' ? 'bg-white text-slate-900 font-semibold shadow-2xs' : 'text-slate-600 hover:text-slate-900' }}">
|
|
<i data-lucide="zap" class="w-3.5 h-3.5"></i>
|
|
<span>Los Model</span>
|
|
</a>
|
|
|
|
<a href="{{ route('admin.makerworld.index', ['tab' => 'auth']) }}" class="px-3 py-1.5 rounded-lg transition flex items-center space-x-1.5 {{ $currentTab === 'auth' ? 'bg-white text-slate-900 font-semibold shadow-2xs' : 'text-slate-600 hover:text-slate-900' }}">
|
|
<i data-lucide="key" class="w-3.5 h-3.5"></i>
|
|
<span>MakerWorld Login</span>
|
|
@if($isAuthenticated)
|
|
<span class="w-1.5 h-1.5 rounded-full bg-emerald-500"></span>
|
|
@endif
|
|
</a>
|
|
</div>
|
|
|
|
<!-- TAB 1: COLLECTIONS & AUTO-SYNC -->
|
|
@if($currentTab === 'collections')
|
|
<div class="space-y-6">
|
|
|
|
<!-- Add Collection Form -->
|
|
<div class="bg-white rounded-2xl p-6 border border-slate-200/80 shadow-xs">
|
|
<div class="max-w-3xl">
|
|
<div class="flex items-center space-x-2 text-xs font-semibold text-slate-700 mb-1">
|
|
<i data-lucide="plus" class="w-3.5 h-3.5 text-slate-500"></i>
|
|
<span>Nieuwe collectie koppelen</span>
|
|
</div>
|
|
<h2 class="text-base font-bold text-slate-900">MakerWorld Collectie toevoegen aan Auto-Sync</h2>
|
|
<p class="text-xs text-slate-500 mt-0.5">
|
|
Voer een collectie URL in of je gebruikersprofiel <code class="text-slate-700 font-mono bg-slate-100 px-1 py-0.5 rounded">https://makerworld.com/nl/@user_1718037659/collections</code>.
|
|
</p>
|
|
|
|
<form action="{{ route('admin.makerworld.collections.add') }}" method="POST" class="mt-4 space-y-3.5">
|
|
@csrf
|
|
|
|
<div>
|
|
<label class="block text-xs font-medium text-slate-700 mb-1.5">
|
|
Collectie URL, ID of Gebruikersprofiel
|
|
</label>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-slate-400">
|
|
<i data-lucide="link" class="w-4 h-4"></i>
|
|
</div>
|
|
<input
|
|
type="text"
|
|
name="collection_input"
|
|
value="{{ old('collection_input', 'https://makerworld.com/nl/@user_1718037659/collections') }}"
|
|
placeholder="bijv. https://makerworld.com/nl/@user_1718037659/collections"
|
|
class="w-full pl-9 pr-3.5 py-2.5 bg-slate-50 border border-slate-200 rounded-xl text-slate-900 placeholder-slate-400 focus:bg-white focus:outline-none focus:ring-2 focus:ring-slate-900/10 focus:border-slate-900 text-xs font-mono"
|
|
required
|
|
>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 pt-1">
|
|
<div class="flex items-center space-x-4 text-xs text-slate-600">
|
|
<label class="flex items-center space-x-2 cursor-pointer">
|
|
<input type="checkbox" name="is_active_sync" value="1" checked class="w-4 h-4 rounded text-slate-900 border-slate-300 focus:ring-slate-900">
|
|
<span>Elke 10 minuten synchroniseren</span>
|
|
</label>
|
|
|
|
<label class="flex items-center space-x-2 cursor-pointer">
|
|
<input type="checkbox" name="sync_now" value="1" checked class="w-4 h-4 rounded text-slate-900 border-slate-300 focus:ring-slate-900">
|
|
<span>Direct importeren</span>
|
|
</label>
|
|
</div>
|
|
|
|
<button type="submit" class="px-4 py-2 bg-slate-900 hover:bg-slate-800 text-white font-medium rounded-xl text-xs transition flex items-center justify-center space-x-1.5 shadow-xs shrink-0 cursor-pointer">
|
|
<i data-lucide="download" class="w-3.5 h-3.5"></i>
|
|
<span>Koppelen & Synchroniseren</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tracked Collections List -->
|
|
<div class="space-y-3">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h2 class="text-sm font-bold text-slate-900">Actief gevolgde collecties ({{ $trackedCollections->count() }})</h2>
|
|
<p class="text-xs text-slate-500">
|
|
Prints uit deze collecties komen binnen als concepten in <a href="{{ route('admin.makerworld.staging') }}" class="text-slate-900 underline font-medium">Artikel Beheer</a>.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
@if($trackedCollections->isEmpty())
|
|
<div class="text-center py-10 bg-white rounded-2xl border border-slate-200/80 p-6">
|
|
<div class="w-10 h-10 rounded-xl bg-slate-100 flex items-center justify-center text-slate-400 mx-auto mb-2">
|
|
<i data-lucide="folder-x" class="w-5 h-5"></i>
|
|
</div>
|
|
<h3 class="text-xs font-semibold text-slate-800">Nog geen collecties gekoppeld</h3>
|
|
<p class="text-xs text-slate-500 max-w-sm mx-auto mt-0.5">
|
|
Koppel hierboven je profiel om automatische 10-minuten import te starten.
|
|
</p>
|
|
</div>
|
|
@else
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
@foreach($trackedCollections as $collection)
|
|
<div class="bg-white rounded-2xl border border-slate-200/80 overflow-hidden flex flex-col justify-between shadow-2xs hover:border-slate-300 transition">
|
|
<div>
|
|
<!-- Cover -->
|
|
<div class="relative h-36 bg-slate-100 overflow-hidden">
|
|
@if($collection->cover_url)
|
|
<img src="{{ $collection->cover_url }}" alt="{{ $collection->name }}" class="w-full h-full object-cover">
|
|
@else
|
|
<div class="w-full h-full flex items-center justify-center bg-slate-100 text-slate-400">
|
|
<i data-lucide="image" class="w-8 h-8"></i>
|
|
</div>
|
|
@endif
|
|
<div class="absolute inset-0 bg-gradient-to-t from-slate-950/70 via-transparent to-transparent"></div>
|
|
|
|
<!-- Badge -->
|
|
<div class="absolute top-2.5 right-2.5">
|
|
@if($collection->is_active_sync)
|
|
<span class="px-2 py-0.5 rounded-full text-[10px] font-semibold bg-emerald-500/90 text-white backdrop-blur flex items-center space-x-1 shadow-xs">
|
|
<span class="w-1.5 h-1.5 rounded-full bg-white animate-pulse"></span>
|
|
<span>10m Sync</span>
|
|
</span>
|
|
@else
|
|
<span class="px-2 py-0.5 rounded-full text-[10px] font-medium bg-slate-900/80 text-slate-300 backdrop-blur">
|
|
Gepauzeerd
|
|
</span>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="absolute bottom-2.5 left-3 right-3 text-white">
|
|
<div class="text-[10px] text-slate-300 font-mono">
|
|
ID: #{{ $collection->makerworld_collection_id }} • {{ $collection->user_handle ?? 'MakerWorld' }}
|
|
</div>
|
|
<h3 class="text-sm font-bold truncate" title="{{ $collection->name }}">
|
|
{{ $collection->name }}
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Body Stats -->
|
|
<div class="p-4 space-y-3">
|
|
@if($collection->description)
|
|
<p class="text-xs text-slate-500 line-clamp-2">
|
|
{{ $collection->description }}
|
|
</p>
|
|
@endif
|
|
|
|
<div class="grid grid-cols-3 gap-2 py-2 px-3 bg-slate-50 rounded-xl text-center text-xs">
|
|
<div>
|
|
<div class="text-[10px] text-slate-400 font-medium">Totaal</div>
|
|
<div class="font-bold text-slate-800">{{ $collection->items_count }}</div>
|
|
</div>
|
|
<div>
|
|
<div class="text-[10px] text-amber-600 font-medium">Concept</div>
|
|
<div class="font-bold text-amber-700">{{ $collection->draft_products_count }}</div>
|
|
</div>
|
|
<div>
|
|
<div class="text-[10px] text-emerald-600 font-medium">Live</div>
|
|
<div class="font-bold text-emerald-700">{{ $collection->published_products_count }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-[11px] text-slate-500 space-y-0.5">
|
|
<div class="flex items-center justify-between">
|
|
<span>Laatste controle:</span>
|
|
<span class="font-mono text-slate-700 font-medium">
|
|
{{ $collection->last_synced_at ? $collection->last_synced_at->diffForHumans() : 'Nog niet' }}
|
|
@if($collection->last_synced_at)
|
|
<span class="text-[10px] text-slate-400 font-normal">({{ $collection->last_synced_at->format('H:i') }})</span>
|
|
@endif
|
|
</span>
|
|
</div>
|
|
@if($collection->last_sync_message)
|
|
<div class="text-[10px] text-slate-400 truncate" title="{{ $collection->last_sync_message }}">
|
|
Status: {{ $collection->last_sync_message }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="p-3 bg-slate-50/60 border-t border-slate-100 flex items-center justify-between gap-2">
|
|
<div class="flex items-center space-x-1.5">
|
|
<form action="{{ route('admin.makerworld.collections.sync', $collection) }}" method="POST">
|
|
@csrf
|
|
<button type="submit" class="px-2.5 py-1.5 rounded-lg bg-white border border-slate-200 text-slate-700 hover:text-slate-900 text-xs font-medium transition flex items-center space-x-1 cursor-pointer">
|
|
<i data-lucide="refresh-cw" class="w-3 h-3 text-slate-500"></i>
|
|
<span>Sync nu</span>
|
|
</button>
|
|
</form>
|
|
|
|
<form action="{{ route('admin.makerworld.collections.toggle', $collection) }}" method="POST">
|
|
@csrf
|
|
<button type="submit" class="px-2 py-1.5 rounded-lg text-xs font-medium transition border cursor-pointer {{ $collection->is_active_sync ? 'bg-white text-slate-600 border-slate-200 hover:text-slate-900' : 'bg-emerald-50 text-emerald-700 border-emerald-200 hover:bg-emerald-100' }}">
|
|
{{ $collection->is_active_sync ? 'Pauzeren' : 'Inschakelen' }}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
<form action="{{ route('admin.makerworld.collections.delete', $collection) }}" method="POST" onsubmit="return confirm('Weet je zeker dat je deze collectie wilt ontkoppelen?');">
|
|
@csrf
|
|
@method('DELETE')
|
|
<button type="submit" title="Collectie verwijderen" class="p-1.5 rounded-lg text-slate-400 hover:text-rose-600 hover:bg-rose-50 transition cursor-pointer">
|
|
<i data-lucide="trash-2" class="w-3.5 h-3.5"></i>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
</div>
|
|
@endif
|
|
|
|
<!-- TAB: COMMUNITY & POPULAIRE MODELLEN -->
|
|
@if(in_array($currentTab, ['community', 'favorites']))
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h2 class="text-base font-bold text-slate-900">Populaire MakerWorld Modellen</h2>
|
|
<p class="text-xs text-slate-500 mt-0.5">Direct importeren naar je catalogus of artikelbeheer.</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
|
|
@forelse($models ?? [] as $model)
|
|
@php
|
|
$mId = $model['id'] ?? 0;
|
|
$cover = $model['cover'] ?? $model['coverUrl'] ?? '';
|
|
$title = $model['title'] ?? 'MakerWorld Model #' . $mId;
|
|
$author = $model['designCreator']['name'] ?? $model['designCreator']['handle'] ?? 'MakerWorld';
|
|
@endphp
|
|
<div class="bg-white rounded-2xl border border-slate-200/80 overflow-hidden shadow-2xs flex flex-col justify-between">
|
|
<div class="aspect-4/3 bg-slate-100 overflow-hidden relative">
|
|
@if($cover)
|
|
<img src="{{ $cover }}" alt="{{ $title }}" class="w-full h-full object-cover">
|
|
@else
|
|
<div class="w-full h-full flex items-center justify-center text-slate-300">
|
|
<i data-lucide="image" class="w-8 h-8"></i>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
<div class="p-3.5 space-y-2 flex-1 flex flex-col justify-between">
|
|
<div>
|
|
<div class="text-[10px] text-slate-400 font-mono">#{{ $mId }} • {{ $author }}</div>
|
|
<h3 class="text-xs font-semibold text-slate-900 line-clamp-2 mt-0.5" title="{{ $title }}">{{ $title }}</h3>
|
|
</div>
|
|
<form action="{{ route('admin.makerworld.import') }}" method="POST">
|
|
@csrf
|
|
<input type="hidden" name="makerworld_id" value="{{ $mId }}">
|
|
<button type="submit" class="w-full py-1.5 px-3 rounded-lg bg-slate-900 hover:bg-slate-800 text-white font-medium text-xs transition cursor-pointer shadow-xs">
|
|
Importeren
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
@empty
|
|
<div class="col-span-full py-12 text-center text-slate-400 text-xs bg-white rounded-2xl border border-slate-200">
|
|
Geen modellen gevonden in dit overzicht.
|
|
</div>
|
|
@endforelse
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- TAB 2: QUICK SINGLE MODEL IMPORT -->
|
|
@if($currentTab === 'quick')
|
|
<div class="bg-white rounded-2xl p-6 border border-slate-200/80 shadow-xs space-y-4">
|
|
<div>
|
|
<h2 class="text-base font-bold text-slate-900 flex items-center space-x-2">
|
|
<i data-lucide="zap" class="w-4 h-4 text-slate-700"></i>
|
|
<span>Los model importeren</span>
|
|
</h2>
|
|
<p class="text-xs text-slate-500 mt-0.5">
|
|
Plak de URL van een specifiek MakerWorld model (bijv. <code class="text-slate-700 font-mono bg-slate-100 px-1 py-0.5 rounded">https://makerworld.com/nl/models/55866</code>) om het direct op te halen met alle foto's en printgegevens.
|
|
</p>
|
|
</div>
|
|
|
|
<form @submit.prevent="fetchQuickPreview()" class="flex flex-col sm:flex-row gap-2.5">
|
|
<div class="relative flex-1">
|
|
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-slate-400">
|
|
<i data-lucide="link" class="w-4 h-4"></i>
|
|
</div>
|
|
<input
|
|
type="text"
|
|
x-model="quickInput"
|
|
placeholder="https://makerworld.com/nl/models/55866 of 55866..."
|
|
class="w-full pl-9 pr-3.5 py-2.5 bg-slate-50 border border-slate-200 rounded-xl text-slate-900 placeholder-slate-400 focus:bg-white focus:outline-none focus:ring-2 focus:ring-slate-900/10 focus:border-slate-900 text-xs font-mono"
|
|
required
|
|
>
|
|
</div>
|
|
<button
|
|
type="submit"
|
|
:disabled="isLoadingQuick"
|
|
class="px-4 py-2.5 bg-slate-900 hover:bg-slate-800 disabled:opacity-50 text-white font-medium rounded-xl text-xs flex items-center justify-center space-x-1.5 shadow-xs transition shrink-0 cursor-pointer"
|
|
>
|
|
<template x-if="isLoadingQuick">
|
|
<div class="flex items-center space-x-1.5">
|
|
<i data-lucide="loader-2" class="w-3.5 h-3.5 animate-spin"></i>
|
|
<span>Ophalen...</span>
|
|
</div>
|
|
</template>
|
|
<template x-if="!isLoadingQuick">
|
|
<div class="flex items-center space-x-1.5">
|
|
<i data-lucide="search" class="w-3.5 h-3.5"></i>
|
|
<span>Gegevens ophalen</span>
|
|
</div>
|
|
</template>
|
|
</button>
|
|
</form>
|
|
|
|
<!-- Preview Area -->
|
|
<div x-show="quickPreview" x-cloak class="mt-4 p-5 rounded-2xl bg-slate-50 border border-slate-200">
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-5">
|
|
<div>
|
|
<img :src="quickPreview?.model?.image_url" alt="" class="w-full aspect-square object-cover rounded-xl bg-white border border-slate-200">
|
|
<div class="mt-2 flex gap-1.5 overflow-x-auto py-1">
|
|
<template x-for="(pic, idx) in quickPreview?.model?.gallery_images" :key="idx">
|
|
<img :src="pic" alt="" class="w-10 h-10 object-cover rounded-lg border border-slate-200 shrink-0">
|
|
</template>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="md:col-span-2 space-y-3">
|
|
<div>
|
|
<div class="text-[11px] font-semibold text-slate-500 font-mono" x-text="'MakerWorld #' + quickPreview?.model?.makerworld_id"></div>
|
|
<h3 class="text-base font-bold text-slate-900" x-text="quickPreview?.model?.name"></h3>
|
|
<p class="text-xs text-slate-500" x-text="'Maker: ' + quickPreview?.model?.makerworld_author"></p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-3 gap-2.5 p-3 rounded-xl bg-white border border-slate-200 text-xs">
|
|
<div>
|
|
<span class="text-slate-400 block text-[10px]">Printtijd</span>
|
|
<span class="font-bold text-slate-800" x-text="(quickPreview?.model?.print_time_hours || '?') + ' uur'"></span>
|
|
</div>
|
|
<div>
|
|
<span class="text-slate-400 block text-[10px]">Gewicht</span>
|
|
<span class="font-bold text-slate-800" x-text="(quickPreview?.model?.weight_grams || '?') + ' gram'"></span>
|
|
</div>
|
|
<div>
|
|
<span class="text-slate-400 block text-[10px]">Adviesprijs</span>
|
|
<span class="font-bold text-slate-900" x-text="'€ ' + quickPreview?.model?.base_price"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Import form -->
|
|
<form action="{{ route('admin.makerworld.import') }}" method="POST" class="pt-3 border-t border-slate-200 flex flex-wrap gap-3 items-end">
|
|
@csrf
|
|
<input type="hidden" name="makerworld_id" :value="quickPreview?.model?.makerworld_id">
|
|
|
|
<div class="w-44">
|
|
<label class="block text-[11px] font-medium text-slate-600 mb-1">Categorie</label>
|
|
<select name="category_id" class="w-full px-2.5 py-1.5 bg-white border border-slate-200 rounded-lg text-slate-900 text-xs">
|
|
@foreach($categories as $cat)
|
|
<option value="{{ $cat->id }}">{{ $cat->name }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
|
|
<div class="w-28">
|
|
<label class="block text-[11px] font-medium text-slate-600 mb-1">Prijs (€)</label>
|
|
<input type="number" step="0.01" name="custom_price" :value="quickPreview?.model?.base_price" class="w-full px-2.5 py-1.5 bg-white border border-slate-200 rounded-lg text-slate-900 text-xs font-semibold">
|
|
</div>
|
|
|
|
<div class="flex items-center space-x-2">
|
|
<button type="submit" name="status" value="published" class="px-3.5 py-1.5 bg-slate-900 hover:bg-slate-800 text-white font-medium rounded-lg text-xs transition shadow-xs cursor-pointer">
|
|
Direct Publiceren
|
|
</button>
|
|
<button type="submit" name="status" value="draft" class="px-3.5 py-1.5 bg-white hover:bg-slate-50 text-slate-700 font-medium rounded-lg text-xs transition border border-slate-200 cursor-pointer">
|
|
Naar Concepten
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- TAB 3: AUTH & CREDENTIALS -->
|
|
@if($currentTab === 'auth')
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<!-- Login with MakerWorld Credentials -->
|
|
<div class="bg-white rounded-2xl p-6 border border-slate-200/80 shadow-xs space-y-4">
|
|
<div class="flex items-center space-x-3">
|
|
<div class="w-10 h-10 rounded-xl bg-slate-100 text-slate-700 flex items-center justify-center">
|
|
<i data-lucide="shield-check" class="w-5 h-5"></i>
|
|
</div>
|
|
<div>
|
|
<h2 class="text-sm font-bold text-slate-900">Inloggen met MakerWorld</h2>
|
|
<p class="text-xs text-slate-500">Bambu Lab / MakerWorld inloggegevens</p>
|
|
</div>
|
|
</div>
|
|
|
|
<form action="{{ route('admin.makerworld.login') }}" method="POST" class="space-y-3 pt-1">
|
|
@csrf
|
|
<div>
|
|
<label class="block text-xs font-medium text-slate-700 mb-1">E-mailadres MakerWorld</label>
|
|
<input type="text" name="account" value="{{ old('account', 'info@jouwdriedee.nl') }}" class="w-full px-3 py-2 bg-slate-50 border border-slate-200 rounded-xl text-slate-900 text-xs focus:bg-white focus:outline-none focus:ring-2 focus:ring-slate-900/10 focus:border-slate-900" required>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-xs font-medium text-slate-700 mb-1">Wachtwoord</label>
|
|
<input type="password" name="password" class="w-full px-3 py-2 bg-slate-50 border border-slate-200 rounded-xl text-slate-900 text-xs focus:bg-white focus:outline-none focus:ring-2 focus:ring-slate-900/10 focus:border-slate-900" required>
|
|
</div>
|
|
|
|
<button type="submit" class="w-full py-2.5 bg-slate-900 hover:bg-slate-800 text-white font-medium rounded-xl text-xs transition shadow-xs cursor-pointer">
|
|
Inloggen bij MakerWorld
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Or Paste Token Directly -->
|
|
<div class="bg-white rounded-2xl p-6 border border-slate-200/80 shadow-xs space-y-4">
|
|
<div class="flex items-center space-x-3">
|
|
<div class="w-10 h-10 rounded-xl bg-slate-100 text-slate-700 flex items-center justify-center">
|
|
<i data-lucide="key" class="w-5 h-5"></i>
|
|
</div>
|
|
<div>
|
|
<h2 class="text-sm font-bold text-slate-900">MakerWorld Bearer Token</h2>
|
|
<p class="text-xs text-slate-500">Plak direct je MakerWorld JWT token</p>
|
|
</div>
|
|
</div>
|
|
|
|
<form action="{{ route('admin.makerworld.token') }}" method="POST" class="space-y-3 pt-1">
|
|
@csrf
|
|
<div>
|
|
<label class="block text-xs font-medium text-slate-700 mb-1">Access Token</label>
|
|
<textarea name="token" rows="3" placeholder="eyJhbGciOi..." class="w-full px-3 py-2 bg-slate-50 border border-slate-200 rounded-xl text-slate-900 text-xs font-mono focus:bg-white focus:outline-none focus:ring-2 focus:ring-slate-900/10 focus:border-slate-900" required></textarea>
|
|
</div>
|
|
|
|
<button type="submit" class="w-full py-2.5 bg-white hover:bg-slate-50 text-slate-800 font-medium rounded-xl text-xs transition border border-slate-200 cursor-pointer">
|
|
Token Opslaan
|
|
</button>
|
|
</form>
|
|
|
|
@if($isAuthenticated)
|
|
<div class="pt-3 border-t border-slate-100 flex items-center justify-between">
|
|
<span class="text-xs text-emerald-600 font-medium flex items-center space-x-1.5">
|
|
<span class="w-2 h-2 rounded-full bg-emerald-500"></span>
|
|
<span>Actief verbonden</span>
|
|
</span>
|
|
<form action="{{ route('admin.makerworld.disconnect') }}" method="POST">
|
|
@csrf
|
|
<button type="submit" class="text-xs text-rose-600 hover:underline font-medium cursor-pointer">
|
|
Ontkoppelen
|
|
</button>
|
|
</form>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
</div>
|
|
|
|
<script>
|
|
function makerWorldSyncApp() {
|
|
return {
|
|
quickInput: '',
|
|
isLoadingQuick: false,
|
|
quickPreview: null,
|
|
|
|
async fetchQuickPreview() {
|
|
if (!this.quickInput.trim()) return;
|
|
this.isLoadingQuick = true;
|
|
this.quickPreview = null;
|
|
|
|
try {
|
|
const res = await fetch(`{{ route('admin.makerworld.preview') }}?query=${encodeURIComponent(this.quickInput.trim())}`);
|
|
const data = await res.json();
|
|
if (res.ok) {
|
|
this.quickPreview = data;
|
|
} else {
|
|
alert(data.error || 'Kon model niet ophalen.');
|
|
}
|
|
} catch (err) {
|
|
alert('Fout bij ophalen van model: ' + err.message);
|
|
} finally {
|
|
this.isLoadingQuick = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
@endsection
|