fix(admin): Clean up store detail and intelligence pages

- Remove Update dropdown from DispensaryDetail page
- Remove Crawl Now button from StoreDetailPage
- Change "Last Crawl" to "Last Updated" on both detail pages
- Tone down emerald colors on StoreDetailPage (use gray borders/tabs)
- Simplify THC/CBD/Stock badges to plain text
- Remove duplicate state dropdown from IntelligenceStores filters
- Make store rows clickable in IntelligenceStores

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Kelly
2025-12-10 23:42:50 -07:00
parent 5b34b5a78c
commit b7d33e1cbf
5 changed files with 29 additions and 129 deletions

View File

@@ -204,47 +204,6 @@ export function DispensaryDetail() {
Back to Dispensaries Back to Dispensaries
</button> </button>
{/* Update Dropdown */}
<div className="relative">
<button
onClick={() => setShowUpdateDropdown(!showUpdateDropdown)}
disabled={isUpdating}
className="flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed"
>
<RefreshCw className={`w-4 h-4 ${isUpdating ? 'animate-spin' : ''}`} />
{isUpdating ? 'Updating...' : 'Update'}
{!isUpdating && <ChevronDown className="w-4 h-4" />}
</button>
{showUpdateDropdown && !isUpdating && (
<div className="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg border border-gray-200 z-10">
<button
onClick={() => handleUpdate('products')}
className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-t-lg"
>
Products
</button>
<button
onClick={() => handleUpdate('brands')}
className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
>
Brands
</button>
<button
onClick={() => handleUpdate('specials')}
className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
>
Specials
</button>
<button
onClick={() => handleUpdate('all')}
className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-b-lg border-t border-gray-200"
>
All
</button>
</div>
)}
</div>
</div> </div>
{/* Dispensary Header */} {/* Dispensary Header */}
@@ -266,7 +225,7 @@ export function DispensaryDetail() {
<div className="flex items-center gap-2 text-sm text-gray-600 bg-gray-50 px-4 py-2 rounded-lg"> <div className="flex items-center gap-2 text-sm text-gray-600 bg-gray-50 px-4 py-2 rounded-lg">
<Calendar className="w-4 h-4" /> <Calendar className="w-4 h-4" />
<div> <div>
<span className="font-medium">Last Crawl Date:</span> <span className="font-medium">Last Updated:</span>
<span className="ml-2"> <span className="ml-2">
{dispensary.last_menu_scrape {dispensary.last_menu_scrape
? new Date(dispensary.last_menu_scrape).toLocaleDateString('en-US', { ? new Date(dispensary.last_menu_scrape).toLocaleDateString('en-US', {

View File

@@ -140,14 +140,14 @@ export function IntelligenceBrands() {
</button> </button>
<button <button
onClick={() => navigate('/admin/intelligence/stores')} onClick={() => navigate('/admin/intelligence/stores')}
className="btn btn-sm btn-outline gap-1" className="btn btn-sm gap-1 bg-white border-gray-300 text-gray-700 hover:bg-gray-100"
> >
<MapPin className="w-4 h-4" /> <MapPin className="w-4 h-4" />
<span>Stores</span> <span>Stores</span>
</button> </button>
<button <button
onClick={() => navigate('/admin/intelligence/pricing')} onClick={() => navigate('/admin/intelligence/pricing')}
className="btn btn-sm btn-outline gap-1" className="btn btn-sm gap-1 bg-white border-gray-300 text-gray-700 hover:bg-gray-100"
> >
<DollarSign className="w-4 h-4" /> <DollarSign className="w-4 h-4" />
<span>Pricing</span> <span>Pricing</span>

View File

@@ -121,14 +121,14 @@ export function IntelligencePricing() {
<div className="flex gap-1"> <div className="flex gap-1">
<button <button
onClick={() => navigate('/admin/intelligence/brands')} onClick={() => navigate('/admin/intelligence/brands')}
className="btn btn-sm btn-outline gap-1" className="btn btn-sm gap-1 bg-white border-gray-300 text-gray-700 hover:bg-gray-100"
> >
<Building2 className="w-4 h-4" /> <Building2 className="w-4 h-4" />
<span>Brands</span> <span>Brands</span>
</button> </button>
<button <button
onClick={() => navigate('/admin/intelligence/stores')} onClick={() => navigate('/admin/intelligence/stores')}
className="btn btn-sm btn-outline gap-1" className="btn btn-sm gap-1 bg-white border-gray-300 text-gray-700 hover:bg-gray-100"
> >
<MapPin className="w-4 h-4" /> <MapPin className="w-4 h-4" />
<span>Stores</span> <span>Stores</span>

View File

@@ -146,7 +146,7 @@ export function IntelligenceStores() {
<div className="flex gap-1"> <div className="flex gap-1">
<button <button
onClick={() => navigate('/admin/intelligence/brands')} onClick={() => navigate('/admin/intelligence/brands')}
className="btn btn-sm btn-outline gap-1" className="btn btn-sm gap-1 bg-white border-gray-300 text-gray-700 hover:bg-gray-100"
> >
<Building2 className="w-4 h-4" /> <Building2 className="w-4 h-4" />
<span>Brands</span> <span>Brands</span>
@@ -159,7 +159,7 @@ export function IntelligenceStores() {
</button> </button>
<button <button
onClick={() => navigate('/admin/intelligence/pricing')} onClick={() => navigate('/admin/intelligence/pricing')}
className="btn btn-sm btn-outline gap-1" className="btn btn-sm gap-1 bg-white border-gray-300 text-gray-700 hover:bg-gray-100"
> >
<DollarSign className="w-4 h-4" /> <DollarSign className="w-4 h-4" />
<span>Pricing</span> <span>Pricing</span>
@@ -220,26 +220,6 @@ export function IntelligenceStores() {
className="input input-bordered input-sm w-full pl-10" className="input input-bordered input-sm w-full pl-10"
/> />
</div> </div>
<div className="dropdown">
<button tabIndex={0} className="btn btn-sm btn-outline gap-2">
{stateLabel}
<ChevronDown className="w-4 h-4" />
</button>
<ul tabIndex={0} className="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-40 max-h-60 overflow-y-auto">
<li>
<a onClick={() => setSelectedState(null)} className={isAllStates ? 'active' : ''}>
All States
</a>
</li>
{localStates.map(state => (
<li key={state}>
<a onClick={() => setSelectedState(state)} className={selectedState === state ? 'active' : ''}>
{state}
</a>
</li>
))}
</ul>
</div>
<span className="text-sm text-gray-500"> <span className="text-sm text-gray-500">
Showing {filteredStores.length} of {stores.length} stores Showing {filteredStores.length} of {stores.length} stores
</span> </span>
@@ -273,7 +253,7 @@ export function IntelligenceStores() {
<tr <tr
key={store.id} key={store.id}
className="hover:bg-gray-50 cursor-pointer" className="hover:bg-gray-50 cursor-pointer"
onClick={() => navigate(`/admin/orchestrator/stores?storeId=${store.id}`)} onClick={() => navigate(`/stores/list/${store.id}`)}
> >
<td> <td>
<span className="font-medium">{store.name}</span> <span className="font-medium">{store.name}</span>

View File

@@ -153,29 +153,6 @@ export function StoreDetailPage() {
Back to Stores Back to Stores
</button> </button>
{/* Update Button */}
<div className="relative">
<button
onClick={() => setShowUpdateDropdown(!showUpdateDropdown)}
disabled={isUpdating}
className="flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed"
>
<RefreshCw className={`w-4 h-4 ${isUpdating ? 'animate-spin' : ''}`} />
{isUpdating ? 'Crawling...' : 'Crawl Now'}
{!isUpdating && <ChevronDown className="w-4 h-4" />}
</button>
{showUpdateDropdown && !isUpdating && (
<div className="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg border border-gray-200 z-10">
<button
onClick={handleCrawl}
className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg"
>
Start Full Crawl
</button>
</div>
)}
</div>
</div> </div>
{/* Store Header */} {/* Store Header */}
@@ -200,7 +177,7 @@ export function StoreDetailPage() {
<div className="flex items-center gap-2 text-sm text-gray-600 bg-gray-50 px-4 py-2 rounded-lg"> <div className="flex items-center gap-2 text-sm text-gray-600 bg-gray-50 px-4 py-2 rounded-lg">
<Clock className="w-4 h-4" /> <Clock className="w-4 h-4" />
<div> <div>
<span className="font-medium">Last Crawl:</span> <span className="font-medium">Last Updated:</span>
<span className="ml-2"> <span className="ml-2">
{lastCrawl?.completed_at {lastCrawl?.completed_at
? new Date(lastCrawl.completed_at).toLocaleDateString('en-US', { ? new Date(lastCrawl.completed_at).toLocaleDateString('en-US', {
@@ -212,15 +189,6 @@ export function StoreDetailPage() {
}) })
: 'Never'} : 'Never'}
</span> </span>
{lastCrawl?.status && (
<span className={`ml-2 px-2 py-0.5 rounded text-xs ${
lastCrawl.status === 'completed' ? 'bg-green-100 text-green-800' :
lastCrawl.status === 'failed' ? 'bg-red-100 text-red-800' :
'bg-yellow-100 text-yellow-800'
}`}>
{lastCrawl.status}
</span>
)}
</div> </div>
</div> </div>
</div> </div>
@@ -282,8 +250,8 @@ export function StoreDetailPage() {
setStockFilter('in_stock'); setStockFilter('in_stock');
setSearchQuery(''); setSearchQuery('');
}} }}
className={`bg-white rounded-lg border p-4 hover:border-blue-300 hover:shadow-md transition-all cursor-pointer text-left ${ className={`bg-white rounded-lg border p-4 hover:border-gray-300 hover:shadow-md transition-all cursor-pointer text-left ${
stockFilter === 'in_stock' ? 'border-blue-500' : 'border-gray-200' stockFilter === 'in_stock' ? 'border-gray-400' : 'border-gray-200'
}`} }`}
> >
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
@@ -303,8 +271,8 @@ export function StoreDetailPage() {
setStockFilter('out_of_stock'); setStockFilter('out_of_stock');
setSearchQuery(''); setSearchQuery('');
}} }}
className={`bg-white rounded-lg border p-4 hover:border-blue-300 hover:shadow-md transition-all cursor-pointer text-left ${ className={`bg-white rounded-lg border p-4 hover:border-gray-300 hover:shadow-md transition-all cursor-pointer text-left ${
stockFilter === 'out_of_stock' ? 'border-blue-500' : 'border-gray-200' stockFilter === 'out_of_stock' ? 'border-gray-400' : 'border-gray-200'
}`} }`}
> >
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
@@ -320,8 +288,8 @@ export function StoreDetailPage() {
<button <button
onClick={() => setActiveTab('brands')} onClick={() => setActiveTab('brands')}
className={`bg-white rounded-lg border p-4 hover:border-blue-300 hover:shadow-md transition-all cursor-pointer text-left ${ className={`bg-white rounded-lg border p-4 hover:border-gray-300 hover:shadow-md transition-all cursor-pointer text-left ${
activeTab === 'brands' ? 'border-blue-500' : 'border-gray-200' activeTab === 'brands' ? 'border-gray-400' : 'border-gray-200'
}`} }`}
> >
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
@@ -337,8 +305,8 @@ export function StoreDetailPage() {
<button <button
onClick={() => setActiveTab('categories')} onClick={() => setActiveTab('categories')}
className={`bg-white rounded-lg border p-4 hover:border-blue-300 hover:shadow-md transition-all cursor-pointer text-left ${ className={`bg-white rounded-lg border p-4 hover:border-gray-300 hover:shadow-md transition-all cursor-pointer text-left ${
activeTab === 'categories' ? 'border-blue-500' : 'border-gray-200' activeTab === 'categories' ? 'border-gray-400' : 'border-gray-200'
}`} }`}
> >
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
@@ -364,7 +332,7 @@ export function StoreDetailPage() {
}} }}
className={`py-4 px-2 text-sm font-medium border-b-2 ${ className={`py-4 px-2 text-sm font-medium border-b-2 ${
activeTab === 'products' activeTab === 'products'
? 'border-blue-600 text-blue-600' ? 'border-gray-800 text-gray-900'
: 'border-transparent text-gray-600 hover:text-gray-900' : 'border-transparent text-gray-600 hover:text-gray-900'
}`} }`}
> >
@@ -374,7 +342,7 @@ export function StoreDetailPage() {
onClick={() => setActiveTab('brands')} onClick={() => setActiveTab('brands')}
className={`py-4 px-2 text-sm font-medium border-b-2 ${ className={`py-4 px-2 text-sm font-medium border-b-2 ${
activeTab === 'brands' activeTab === 'brands'
? 'border-blue-600 text-blue-600' ? 'border-gray-800 text-gray-900'
: 'border-transparent text-gray-600 hover:text-gray-900' : 'border-transparent text-gray-600 hover:text-gray-900'
}`} }`}
> >
@@ -384,7 +352,7 @@ export function StoreDetailPage() {
onClick={() => setActiveTab('categories')} onClick={() => setActiveTab('categories')}
className={`py-4 px-2 text-sm font-medium border-b-2 ${ className={`py-4 px-2 text-sm font-medium border-b-2 ${
activeTab === 'categories' activeTab === 'categories'
? 'border-blue-600 text-blue-600' ? 'border-gray-800 text-gray-900'
: 'border-transparent text-gray-600 hover:text-gray-900' : 'border-transparent text-gray-600 hover:text-gray-900'
}`} }`}
> >
@@ -433,7 +401,7 @@ export function StoreDetailPage() {
{productsLoading ? ( {productsLoading ? (
<div className="text-center py-8"> <div className="text-center py-8">
<div className="inline-block animate-spin rounded-full h-6 w-6 border-4 border-blue-500 border-t-transparent"></div> <div className="inline-block animate-spin rounded-full h-6 w-6 border-4 border-gray-400 border-t-transparent"></div>
<p className="mt-2 text-sm text-gray-600">Loading products...</p> <p className="mt-2 text-sm text-gray-600">Loading products...</p>
</div> </div>
) : products.length === 0 ? ( ) : products.length === 0 ? (
@@ -485,9 +453,9 @@ export function StoreDetailPage() {
<div className="line-clamp-2" title={product.brand || '-'}>{product.brand || '-'}</div> <div className="line-clamp-2" title={product.brand || '-'}>{product.brand || '-'}</div>
</td> </td>
<td className="whitespace-nowrap"> <td className="whitespace-nowrap">
<span className="badge badge-ghost badge-sm">{product.type || '-'}</span> <span className="text-xs text-gray-500 bg-gray-100 px-1.5 py-0.5 rounded">{product.type || '-'}</span>
{product.subcategory && ( {product.subcategory && (
<span className="badge badge-ghost badge-sm ml-1">{product.subcategory}</span> <span className="text-xs text-gray-500 bg-gray-100 px-1.5 py-0.5 rounded ml-1">{product.subcategory}</span>
)} )}
</td> </td>
<td className="text-right font-semibold whitespace-nowrap"> <td className="text-right font-semibold whitespace-nowrap">
@@ -500,21 +468,14 @@ export function StoreDetailPage() {
`$${product.regular_price}` `$${product.regular_price}`
) : '-'} ) : '-'}
</td> </td>
<td className="text-center whitespace-nowrap"> <td className="text-center whitespace-nowrap text-sm text-gray-700">
{product.thc_percentage ? ( {product.thc_percentage ? `${product.thc_percentage}%` : '-'}
<span className="badge badge-success badge-sm">{product.thc_percentage}%</span>
) : '-'}
</td> </td>
<td className="text-center whitespace-nowrap"> <td className="text-center whitespace-nowrap text-sm text-gray-700">
{product.stock_status === 'in_stock' ? ( {product.stock_status === 'in_stock' ? 'In Stock' :
<span className="badge badge-success badge-sm">In Stock</span> product.stock_status === 'out_of_stock' ? 'Out' : '-'}
) : product.stock_status === 'out_of_stock' ? (
<span className="badge badge-error badge-sm">Out</span>
) : (
<span className="badge badge-warning badge-sm">Unknown</span>
)}
</td> </td>
<td className="text-center whitespace-nowrap"> <td className="text-center whitespace-nowrap text-sm text-gray-700">
{product.total_quantity != null ? product.total_quantity : '-'} {product.total_quantity != null ? product.total_quantity : '-'}
</td> </td>
<td className="whitespace-nowrap text-xs text-gray-500"> <td className="whitespace-nowrap text-xs text-gray-500">