Updated inventory modal styling and added inventory button to card grid
This commit is contained in:
@@ -47,13 +47,6 @@ const catalogs = catalogRows
|
||||
<aside class="col-12 col-md-2 border-end border-secondary bg-dark p-3 d-flex flex-column gap-3">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0 text-uppercase text-secondary fw-bold ls-wide" style="letter-spacing:.08em">Catalogs</h6>
|
||||
<button
|
||||
class="btn btn-purple-secondary fs-7"
|
||||
title="New catalog"
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#newCatalogModal"
|
||||
>+ New</button>
|
||||
</div>
|
||||
|
||||
<ul id="catalogList" class="list-group list-group-flush">
|
||||
@@ -96,12 +89,10 @@ const catalogs = catalogRows
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="col-12 col-md-10 p-4">
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center mb-4">
|
||||
<main class="col-12 col-md-10 mt-4">
|
||||
<div class="d-flex flex-wrap gap-2 mb-4">
|
||||
|
||||
<div class="vr opacity-25 mx-1"></div>
|
||||
|
||||
<a href="/pokemon" class="btn btn-vendor">+ Add Card</a>
|
||||
<a href="/pokemon" class="btn btn-vendor">Add cards</a>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
@@ -164,8 +155,8 @@ const catalogs = catalogRows
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-secondary">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" id="csvUploadBtn">Upload & Preview</button>
|
||||
<button type="button" class="btn btn-outline-danger" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" id="csvUploadBtn">Upload</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -473,7 +473,7 @@ const altSearchUrl = (card: any) => {
|
||||
|
||||
</datalist>
|
||||
<div class="form-text">
|
||||
Type a name or pick an existing catalog.
|
||||
Enter a name or pick an existing catalog.
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
|
||||
@@ -7,8 +7,8 @@ export const prerender = false;
|
||||
import * as util from 'util';
|
||||
|
||||
// auth check for inventory management features
|
||||
//const { canAddInventory } = Astro.locals;
|
||||
const canAddInventory = false;
|
||||
const { canAddInventory } = Astro.locals;
|
||||
// const canAddInventory = false;
|
||||
|
||||
// all the facet fields we want to use for filtering
|
||||
const facetFields:any = {
|
||||
|
||||
@@ -48,7 +48,17 @@ const purchaseDate = inv?.createdAt ? new Date(inv.createdAt).toISOString().spli
|
||||
const marketPrice = sku?.marketPrice != null ? Number(sku.marketPrice) : null;
|
||||
const condition = sku?.condition || 'Near Mint';
|
||||
|
||||
const gain = (purchasePrice != null && marketPrice != null) ? marketPrice - purchasePrice : null;
|
||||
const gain =
|
||||
purchasePrice != null && marketPrice != null
|
||||
? marketPrice - purchasePrice
|
||||
: null;
|
||||
|
||||
const gainPercent =
|
||||
purchasePrice != null &&
|
||||
marketPrice != null &&
|
||||
purchasePrice > 0
|
||||
? ((marketPrice - purchasePrice) / purchasePrice) * 100
|
||||
: null;
|
||||
|
||||
// ── Price history for this SKU's condition only ──────────────────────────
|
||||
const priceHistoryForChart = (sku?.history ?? [])
|
||||
@@ -132,40 +142,105 @@ const altSearchUrl = (card: any) => {
|
||||
<!-- Inventory details + edit column -->
|
||||
<div class="col-sm-12 col-md-7">
|
||||
|
||||
<!-- Static fields from the inventory entry -->
|
||||
<div class="d-flex flex-fill flex-row gap-1 flex-wrap flex-lg-nowrap">
|
||||
<div class="alert alert-dark rounded p-2 flex-fill d-flex flex-column mb-0">
|
||||
<h6 class="mb-auto">Quantity</h6>
|
||||
<p class="mb-0 mt-1">{quantity}</p>
|
||||
</div>
|
||||
<div class="alert alert-dark rounded p-2 flex-fill d-flex flex-column mb-0">
|
||||
<h6 class="mb-auto">Purchase Price</h6>
|
||||
<p class="mb-0 mt-1">{purchasePrice != null ? `$${purchasePrice.toFixed(2)}` : '—'}</p>
|
||||
</div>
|
||||
<div class="alert alert-dark rounded p-2 flex-fill d-flex flex-column mb-0">
|
||||
<h6 class="mb-auto">Condition</h6>
|
||||
<p class="mb-0 mt-1">{condition}</p>
|
||||
</div>
|
||||
<div class="alert alert-dark rounded p-2 flex-fill d-flex flex-column mb-0">
|
||||
<h6 class="mb-auto">Market Price</h6>
|
||||
<p class="mb-0 mt-1">{marketPrice != null ? `$${marketPrice.toFixed(2)}` : '—'}</p>
|
||||
</div>
|
||||
<div class={`alert rounded p-2 flex-fill d-flex flex-column mb-0 ${gain == null ? 'alert-dark' : gain >= 0 ? 'alert-success' : 'alert-danger'}`}>
|
||||
<h6 class="mb-auto">Gain / Loss</h6>
|
||||
<p class="mb-0 mt-1">{gain == null ? '—' : `${gain >= 0 ? '+' : '−'}$${Math.abs(gain).toFixed(2)}`}</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Static fields (left) + editable Note/Catalog (right), side by side -->
|
||||
<div class="row gx-3 gy-2">
|
||||
<!-- Left column: read-only stats -->
|
||||
<div class="col-12 col-lg-6">
|
||||
<label class="form-label">Condition</label>
|
||||
<div class="btn-group condition-input w-100 col-12" role="group" aria-label="Condition">
|
||||
<input
|
||||
type="radio"
|
||||
class="btn-check"
|
||||
name="condition"
|
||||
id="cond-nm"
|
||||
value="Near Mint"
|
||||
autocomplete="off"
|
||||
checked
|
||||
/>
|
||||
<label class="btn btn-cond-nm" for="cond-nm">NM</label>
|
||||
|
||||
<!-- Editable fields: Catalog + Note -->
|
||||
<form data-inventory-edit-form class="mt-3" novalidate>
|
||||
<input type="hidden" name="action" value="update" />
|
||||
<input type="hidden" name="inventoryId" value={inv?.inventoryId} />
|
||||
<input type="hidden" name="cardId" value={card?.cardId} />
|
||||
<input type="hidden" name="quantity" value={quantity} />
|
||||
<input type="hidden" name="purchasePrice" value={purchasePrice ?? 0} />
|
||||
<input
|
||||
type="radio"
|
||||
class="btn-check"
|
||||
name="condition"
|
||||
id="cond-lp"
|
||||
value="Lightly Played"
|
||||
autocomplete="off"
|
||||
disabled
|
||||
/>
|
||||
<label class="btn btn-cond-lp" for="cond-lp">LP</label>
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
class="btn-check"
|
||||
name="condition"
|
||||
id="cond-mp"
|
||||
value="Moderately Played"
|
||||
autocomplete="off"
|
||||
disabled
|
||||
/>
|
||||
<label class="btn btn-cond-mp" for="cond-mp">MP</label>
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
class="btn-check"
|
||||
name="condition"
|
||||
id="cond-hp"
|
||||
value="Heavily Played"
|
||||
autocomplete="off"
|
||||
disabled
|
||||
/>
|
||||
<label class="btn btn-cond-hp" for="cond-hp">HP</label>
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
class="btn-check"
|
||||
name="condition"
|
||||
id="cond-dmg"
|
||||
value="Damaged"
|
||||
autocomplete="off"
|
||||
disabled
|
||||
/>
|
||||
<label class="btn btn-cond-dmg" for="cond-dmg">DMG</label>
|
||||
</div>
|
||||
<p class="mb-1 my-2">Purchased: <span class="text-secondary">{inv.createdAt ? new Date(inv.createdAt).toLocaleDateString() : '—'}</span></p>
|
||||
<div class="d-flex flex-wrap justify-content-center flex-row gap-2">
|
||||
<div class="alert alert-dark d-flex flex-column flex-fill rounded p-2 mb-2">
|
||||
<p class="mb-auto">Purchase Price</p>
|
||||
<h6 class="mb-0 mt-1">{purchasePrice != null ? `$${purchasePrice.toFixed(2)}` : '—'}</h6>
|
||||
</div>
|
||||
<div class="alert alert-dark d-flex flex-column flex-fill rounded p-2 mb-2">
|
||||
<p class="mb-auto">Market Price</p>
|
||||
<h6 class="mb-0 mt-1">{marketPrice != null ? `$${marketPrice.toFixed(2)}` : '—'}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap justify-content-between flex-row gap-2">
|
||||
<div class={`alert rounded p-2 flex-fill ${gain == null ? 'alert-dark' : gain >= 0 ? 'alert-success' : 'alert-danger'}`}>
|
||||
<p class="mb-auto">Gain / Loss ($)</p>
|
||||
<h6 class="mb-0 mt-1">{gain == null ? '—' : `${gain >= 0 ? '+' : '−'}$${Math.abs(gain).toFixed(2)}`}</h6>
|
||||
</div>
|
||||
<div class={`alert rounded p-2 flex-fill ${gainPercent == null ? 'alert-dark' : gainPercent >= 0 ? 'alert-success' : 'alert-danger'}`}>
|
||||
<p class="mb-auto">Gain / Loss (%)</p>
|
||||
<h6 class="mb-0 mt-1">
|
||||
{
|
||||
gainPercent == null
|
||||
? '—'
|
||||
: `${gainPercent >= 0 ? '+' : '−'}${Math.abs(gainPercent).toFixed(2)}%`
|
||||
}
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right column: editable Note + Catalog -->
|
||||
<div class="col-12 col-lg-6">
|
||||
<form data-inventory-edit-form novalidate>
|
||||
<input type="hidden" name="action" value="update" />
|
||||
<input type="hidden" name="inventoryId" value={inv?.inventoryId} />
|
||||
<input type="hidden" name="cardId" value={card?.cardId} />
|
||||
<input type="hidden" name="quantity" value={quantity} />
|
||||
<input type="hidden" name="purchasePrice" value={purchasePrice ?? 0} />
|
||||
|
||||
<div class="row gx-3 gy-2">
|
||||
<div class="col-12 col-lg-5">
|
||||
<label for="catalogName" class="form-label">Catalog</label>
|
||||
<input
|
||||
type="text"
|
||||
@@ -181,27 +256,24 @@ const altSearchUrl = (card: any) => {
|
||||
<datalist id="catalogSuggestions">
|
||||
{catalogs.map(name => <option value={name}></option>)}
|
||||
</datalist>
|
||||
</div>
|
||||
<div class="col-12 col-lg-7">
|
||||
<label for="note" class="form-label">Note</label>
|
||||
|
||||
<label for="note" class="form-label mt-2">Note</label>
|
||||
<textarea
|
||||
class="form-control"
|
||||
id="note"
|
||||
name="note"
|
||||
rows="2"
|
||||
rows="5"
|
||||
maxlength="255"
|
||||
placeholder="e.g. bought at local shop, gift, graded copy…"
|
||||
>{inv?.note ?? ''}</textarea>
|
||||
</div>
|
||||
<div class="col-12 d-flex justify-content-end gap-2 pt-1">
|
||||
<button type="button" class="btn btn-outline-danger" data-inventory-delete>Delete</button>
|
||||
<button type="submit" class="btn btn-success">Save</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Market Price History chart for this condition -->
|
||||
<div class="d-block d-lg-flex gap-1 mt-3 price-chart-container">
|
||||
<div class="d-block d-lg-flex gap-1 mt-2 price-chart-container">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-dark rounded p-2 mb-0">
|
||||
<h6>Market Price History <span class="small text-secondary">({condition})</span></h6>
|
||||
@@ -232,10 +304,14 @@ const altSearchUrl = (card: any) => {
|
||||
</div>
|
||||
|
||||
<!-- External links column -->
|
||||
<div class="col-sm-12 col-md-2 mt-0 mt-md-5 d-flex flex-row flex-md-column">
|
||||
<div class="col-sm-12 col-md-2 mt-0 mt-md-4 d-flex flex-row flex-md-column">
|
||||
<a class="btn btn-dark mb-2 w-100 p-2" href={`https://www.tcgplayer.com/product/${card?.productId}`} target="_blank" onclick="dataLayer.push({'event': 'tcgplayerClick', 'tcgplayerUrl': this.getAttribute('href')});"><img src="/vendors/tcgplayer.webp"> <span class="d-none d-lg-inline">TCGPlayer</span></a>
|
||||
<a class="btn btn-dark mb-2 w-100 p-2" href={`${ebaySearchUrl(card)}`} target="_blank" onclick="dataLayer.push({'event': 'ebayClick', 'ebayUrl': this.getAttribute('href')});"><span set:html={ebay} /></a>
|
||||
<a class="btn btn-dark mb-2 w-100 p-2" href={`${altSearchUrl(card)}`} target="_blank" onclick="dataLayer.push({'event': 'altClick', 'altUrl': this.getAttribute('href')});"><svg width="48" height="20.16" viewBox="0 0 48 20" fill="none"><path d="M14.2761 19.9996H18.5308L11.6934 0.0712891H7.76953L14.2761 19.9996Z" fill="#ffffff"></path><path d="M6.17778 19.9986H6.14536L3.19643 11.2305L0 19.9988L6.17768 19.9989L6.17778 19.9986Z" fill="#ffffff"></path><path d="M24.7842 0H20.6759V19.9661H34.3427V16.5426H24.7842V0Z" fill="#ffffff"></path><path d="M41.6644 3.42355H47.4981V0H31.5033V3.42355H37.5561V19.9661H41.6644V3.42355Z" fill="#ffffff"></path></svg></a>
|
||||
<div class="d-flex gap-2 mt-auto align-items-end justify-content-evenly">
|
||||
<button type="button" class="btn btn-outline-danger flex-fill" data-inventory-delete>Delete</button>
|
||||
<button type="submit" class="btn btn-success flex-fill flex-grow-1">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -243,4 +319,4 @@ const altSearchUrl = (card: any) => {
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
)}
|
||||
)}
|
||||
Reference in New Issue
Block a user