547 lines
20 KiB
PHP
547 lines
20 KiB
PHP
@extends('teamstore-layout.main')
|
|
@section('content')
|
|
@if ($store_array[0]->IsHibernated)
|
|
<script>
|
|
window.location = "../";
|
|
</script>
|
|
@endif
|
|
|
|
<style>
|
|
h2 {
|
|
width: 100%;
|
|
margin: 0;
|
|
padding: 0;
|
|
text-align: center;
|
|
margin-top: 40px;
|
|
margin-bottom: 40px;
|
|
|
|
}
|
|
/* h2:after {
|
|
display: inline-block;
|
|
margin: 0 0 8px 20px;
|
|
height: 3px;
|
|
content: " ";
|
|
text-shadow: none;
|
|
background-color: #000;
|
|
width: 140px;
|
|
}
|
|
h2:before {
|
|
display: inline-block;
|
|
margin: 0 20px 8px 0;
|
|
height: 3px;
|
|
content: " ";
|
|
text-shadow: none;
|
|
background-color: #000;
|
|
width: 140px;
|
|
} */
|
|
h4{
|
|
font-weight: 600;
|
|
}
|
|
p{
|
|
font-size: 12px;
|
|
margin-top: 5px;
|
|
}
|
|
.price{
|
|
font-size: 25px;
|
|
margin: 0 auto;
|
|
color: #333;
|
|
}
|
|
.right{
|
|
float:right;
|
|
border-bottom: 2px solid #4B8E4B;
|
|
}
|
|
.thumbnail{
|
|
/* opacity:0.70; */
|
|
-webkit-transition: all 0.5s;
|
|
transition: all 0.5s;
|
|
}
|
|
.thumbnail:hover{
|
|
opacity:1.00;
|
|
box-shadow: 0px 0px 10px #4bc6ff;
|
|
}
|
|
.line{
|
|
margin-bottom: 5px;
|
|
}
|
|
.thumbnail>img{
|
|
height:201.84px;
|
|
}
|
|
@media screen and (max-width: 770px) {
|
|
.right{
|
|
float:left;
|
|
width: 100%;
|
|
}
|
|
}
|
|
@media screen and (min-width: 768px){
|
|
.container .jumbotron, .container-fluid .jumbotron {
|
|
padding-right: 15px;
|
|
padding-left: 15px;
|
|
}
|
|
}
|
|
.container .jumbotron, .container-fluid .jumbotron{
|
|
border-radius: 0px;
|
|
}
|
|
|
|
|
|
.jumbotron {
|
|
padding-top: 20px;
|
|
padding-bottom: 20px;
|
|
@if($store_array[0]->StoreBanner == null)
|
|
background-image: url("{{ minio_url('uploads/images/teamstore/store-banner-dark.png') }}");
|
|
@else
|
|
background-image: url("{{ minio_url('uploads/images/teamstore/' . $store_array[0]->ImageFolder . '/' . $store_array[0]->StoreBanner) }}");
|
|
@endif
|
|
background-color: #f3f3f3;
|
|
background-position: center;
|
|
background-size: cover;
|
|
width: 100%;
|
|
height: 128px;
|
|
}
|
|
|
|
.store-name{
|
|
|
|
background: rgba(255, 255, 255, 0.9);
|
|
position: absolute;
|
|
padding: 10px;
|
|
min-width: 270px;
|
|
|
|
}
|
|
|
|
@media (min-width: 200px) {
|
|
.jumbotron { height: 50px; }
|
|
}
|
|
|
|
@media (min-width: 400px) {
|
|
.jumbotron { height: 57px; }
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
.jumbotron { height: 100px; }
|
|
}
|
|
|
|
@media (min-width: 992px) {
|
|
.jumbotron { height: 128px; }
|
|
}
|
|
|
|
.product-name-holder{
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
/* ── Category nav ──────────────────────────────────────────────────────── */
|
|
.cat-nav {
|
|
background: #f8f8f8;
|
|
border-bottom: 2px solid #e0e0e0;
|
|
padding: 0;
|
|
margin-bottom: 24px;
|
|
}
|
|
.cat-nav ul {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
.cat-nav > ul > li {
|
|
position: relative;
|
|
}
|
|
.cat-nav > ul > li > a {
|
|
display: block;
|
|
padding: 14px 20px;
|
|
font-weight: 700;
|
|
font-size: 13px;
|
|
text-transform: uppercase;
|
|
color: #222;
|
|
text-decoration: none;
|
|
letter-spacing: .5px;
|
|
border-bottom: 3px solid transparent;
|
|
transition: border-color .2s, color .2s;
|
|
}
|
|
.cat-nav > ul > li > a:hover,
|
|
.cat-nav > ul > li > a.active {
|
|
color: #4B8E4B;
|
|
border-bottom-color: #4B8E4B;
|
|
}
|
|
/* sub-category dropdown */
|
|
.cat-nav .sub-menu {
|
|
display: none;
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 0;
|
|
min-width: 200px;
|
|
background: #fff;
|
|
border: 1px solid #ddd;
|
|
border-top: 3px solid #4B8E4B;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,.12);
|
|
z-index: 999;
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 6px 0;
|
|
}
|
|
.cat-nav > ul > li:hover .sub-menu {
|
|
display: block;
|
|
}
|
|
.cat-nav .sub-menu li a {
|
|
display: block;
|
|
padding: 9px 18px;
|
|
font-size: 13px;
|
|
color: #333;
|
|
text-decoration: none;
|
|
white-space: nowrap;
|
|
}
|
|
.cat-nav .sub-menu li a:hover,
|
|
.cat-nav .sub-menu li a.active {
|
|
background: #f0f9f0;
|
|
color: #4B8E4B;
|
|
}
|
|
.cat-count {
|
|
display: inline-block;
|
|
background: #ddd;
|
|
border-radius: 10px;
|
|
font-size: 11px;
|
|
padding: 1px 7px;
|
|
margin-left: 4px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
/* ── League / conference pill filter (sub-sub-category) ─────────────────── */
|
|
.league-filter {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
padding: 10px 0 14px;
|
|
margin-bottom: 18px;
|
|
border-bottom: 1px solid #e8e8e8;
|
|
align-items: center;
|
|
}
|
|
.league-filter .lf-label {
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
color: #888;
|
|
letter-spacing: .5px;
|
|
margin-right: 4px;
|
|
white-space: nowrap;
|
|
}
|
|
.league-filter a {
|
|
display: inline-block;
|
|
padding: 5px 14px;
|
|
border-radius: 20px;
|
|
background: #f0f0f0;
|
|
color: #333;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
text-decoration: none;
|
|
white-space: nowrap;
|
|
border: 1px solid #ddd;
|
|
transition: background .2s, color .2s, border-color .2s;
|
|
}
|
|
.league-filter a:hover {
|
|
background: #e0f2e0;
|
|
color: #4B8E4B;
|
|
border-color: #4B8E4B;
|
|
}
|
|
.league-filter a.active {
|
|
background: #4B8E4B;
|
|
color: #fff;
|
|
border-color: #4B8E4B;
|
|
}
|
|
[v-cloak] { display: none; }
|
|
</style>
|
|
|
|
<div class="container">
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="jumbotron">
|
|
@if($store_array[0]->StoreBanner == null)
|
|
<div class="store-name">
|
|
<h4>
|
|
<img src="https://img.icons8.com/ios/40/000000/online-store-filled.png">
|
|
{{ $store_array[0]->StoreName }}<br>
|
|
</h4>
|
|
Official Team Store
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<h2>FEATURED PRODUCTS</h2>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- ── Vue category + product grid ─────────────────────────────────────── --}}
|
|
<script>
|
|
window._tsProducts = {!! json_encode(
|
|
collect($product_array)
|
|
->where('PrivacyStatus', 'public')
|
|
->map(function($p) use ($thumbnails) {
|
|
$thumbList = isset($thumbnails) ? $thumbnails : [];
|
|
$thumb = collect($thumbList)->filter(function($t) use ($p) {
|
|
return $t['product_id'] == $p->Id;
|
|
})->first();
|
|
return [
|
|
'id' => $p->Id,
|
|
'name' => $p->ProductName,
|
|
'price' => $p->ProductPrice,
|
|
'url' => $p->ProductURL,
|
|
'img' => $thumb ? $thumb['thumb'] : 'product-image-placeholder.png',
|
|
'folder'=> $thumb ? $thumb['folder'] : '',
|
|
];
|
|
})->values()->toArray(),
|
|
JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT
|
|
) !!};
|
|
window._tsStore = {
|
|
url : {!! json_encode($store_array[0]->StoreUrl, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) !!},
|
|
currency : {!! json_encode($store_array[0]->StoreCurrency, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) !!},
|
|
minoBase : {!! json_encode(rtrim(config('filesystems.disks.minio.url', ''), '/') . '/' . env('MINIO_BUCKET', 'crewsportswear') . '/', JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) !!},
|
|
};
|
|
</script>
|
|
|
|
<div id="ts-app" v-cloak>
|
|
|
|
{{-- ── Category nav ── --}}
|
|
<nav class="cat-nav" v-if="categories.length > 0">
|
|
<ul>
|
|
<li>
|
|
<a href="#" :class="{active: activeCategory===null && activeSubCategory===null}"
|
|
@click.prevent="activeCategory=null; activeSubCategory=null">
|
|
All
|
|
<span class="cat-count">@{{ totalPublic }}</span>
|
|
</a>
|
|
</li>
|
|
<li v-for="cat in categories" :key="cat.name">
|
|
<a href="#"
|
|
:class="{active: activeCategory===cat.name}"
|
|
@click.prevent="selectCategory(cat.name)">
|
|
@{{ cat.name }}
|
|
<span class="cat-count">@{{ cat.count }}</span>
|
|
</a>
|
|
<ul class="sub-menu" v-if="cat.subs.length > 0">
|
|
<li v-for="sub in cat.subs" :key="sub.name">
|
|
<a href="#"
|
|
:class="{active: activeCategory===cat.name && activeSubCategory===sub.name}"
|
|
@click.prevent="selectSub(cat.name, sub.name)">
|
|
@{{ sub.name }}
|
|
<span class="cat-count">@{{ sub.count }}</span>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
|
|
{{-- ── League / conference pill filter ── --}}
|
|
<div class="league-filter" v-if="isLeagueStore && activeCategory !== null && leagues.length > 0">
|
|
<span class="lf-label">League / Conf:</span>
|
|
<a href="#"
|
|
:class="{active: activeLeague === null}"
|
|
@click.prevent="activeLeague = null">All</a>
|
|
<a href="#"
|
|
v-for="lg in leagues" :key="lg.name"
|
|
:class="{active: activeLeague === lg.name}"
|
|
@click.prevent="activeLeague = lg.name">
|
|
@{{ lg.name }}
|
|
<span class="cat-count">@{{ lg.count }}</span>
|
|
</a>
|
|
</div>
|
|
|
|
{{-- ── Announcements (kept outside loop) ── --}}
|
|
@if ($announcement->IsActive)
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="alert alert-info">
|
|
<p><b>Shop Announcements:</b></p>
|
|
{!! nl2br(e($announcement->Announcement)) !!}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
@if($store_array[0]->Id == 174 || $store_array[0]->Id == 175 || $store_array[0]->Id == 178 || $store_array[0]->Id == 179 || $store_array[0]->Id == 177 || $store_array[0]->Id == 189 || $store_array[0]->Id == 176 || $store_array[0]->Id == 190 || $store_array[0]->Id == 191 || $store_array[0]->Id == 192 || $store_array[0]->Id == 194)
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="alert alert-warning">
|
|
<p><b>Please read:</b></p>
|
|
1. All orders will be batch shipped to your school for pick up.<br>
|
|
2. Orders will be batch processed on a weekly basis, please allow 2-3 weeks for delivery.<br>
|
|
3. Masks and gaiters sold on Crew are not intended for medical use. Crew does not make any medical or health claims.<br>
|
|
4. Refunds and exchanges are not allowed due to the hygenic nature of the product.<br>
|
|
@if($store_array[0]->Id == 175)
|
|
5. $1 from every item sold will benefit the 2020-2021 Maine South Schoolwide Fundraiser.
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
{{-- ── Product grid ── --}}
|
|
<div class="row">
|
|
<div class="col-md-12 text-center" v-if="filtered.length === 0">
|
|
<p style="margin:40px 0;color:#888;">No products found in this category.</p>
|
|
</div>
|
|
<div class="col-md-3 col-sm-6" v-for="p in filtered" :key="p.id">
|
|
<span class="thumbnail">
|
|
<a :href="productUrl(p)">
|
|
<img style="height:201.84px;" :src="imgUrl(p)" :alt="p.name">
|
|
</a>
|
|
<h4 class="text-center product-name-holder">@{{ p.name }}</h4>
|
|
<hr class="line">
|
|
<div class="row">
|
|
<div class="col-md-7 col-sm-7">
|
|
<p class="price">@{{ p.price }} <small style="font-size:15px;">@{{ store.currency }}</small></p>
|
|
</div>
|
|
<div class="col-md-5 col-sm-5">
|
|
<a :href="productUrl(p)" class="btn btn-success right">View Details</a>
|
|
</div>
|
|
</div>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
</div>{{-- /ts-app --}}
|
|
|
|
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
|
|
<script>
|
|
(function () {
|
|
// ── sport & item-type keyword maps ──────────────────────────────────
|
|
const SPORTS = [
|
|
'Basketball','Football','Soccer','Baseball','Softball',
|
|
'Volleyball','Hockey','Lacrosse','Wrestling','Tennis',
|
|
'Swimming','Track','Cross Country','Golf','Cheerleading',
|
|
'Dance','Rugby','Bowling','Gymnastics','Cycling',
|
|
];
|
|
const ITEMS = [
|
|
'Jersey','T-Shirt','Tee','Hoodie','Sweatshirt','Jacket',
|
|
'Shorts','Pants','Tank','Top','Pullover','Zip-Up',
|
|
'Hat','Cap','Beanie','Polo','Uniform','Warmup','Pinnie',
|
|
];
|
|
// ── league / conference keyword map ──────────────────────────────────
|
|
// Order matters: more specific phrases first
|
|
const LEAGUES = [
|
|
{ key: 'NBA', terms: ['nba'] },
|
|
{ key: 'NFL', terms: ['nfl'] },
|
|
{ key: 'MLB', terms: ['mlb'] },
|
|
{ key: 'NHL', terms: ['nhl'] },
|
|
{ key: 'MLS', terms: ['mls'] },
|
|
{ key: 'WNBA', terms: ['wnba'] },
|
|
{ key: 'Big Ten', terms: ['big ten','big10','big 10'] },
|
|
{ key: 'ACC', terms: ['acc'] },
|
|
{ key: 'SEC', terms: ['sec'] },
|
|
{ key: 'Big 12', terms: ['big 12','big12'] },
|
|
{ key: 'Pac-12', terms: ['pac-12','pac12','pac 12'] },
|
|
{ key: 'AAC', terms: ['aac'] },
|
|
{ key: 'CUSA', terms: ['cusa','c-usa'] },
|
|
{ key: 'MAC', terms: ['\bmac\b'] },
|
|
{ key: 'Sun Belt',terms: ['sun belt'] },
|
|
{ key: 'Mountain West', terms: ['mountain west','mwc'] },
|
|
];
|
|
|
|
function classify(name) {
|
|
const n = name.toLowerCase();
|
|
const sport = SPORTS.find(s => n.includes(s.toLowerCase())) || 'Other';
|
|
const item = ITEMS.find(i => n.includes(i.toLowerCase())) || 'Other';
|
|
let league = null;
|
|
for (const lg of LEAGUES) {
|
|
if (lg.terms.some(t => {
|
|
try { return new RegExp(t, 'i').test(n); } catch(e) { return n.includes(t); }
|
|
})) {
|
|
league = lg.key;
|
|
break;
|
|
}
|
|
}
|
|
return { sport, item, league };
|
|
}
|
|
|
|
const { createApp } = Vue;
|
|
const store = window._tsStore || { url:'', currency:'', minoBase:'' };
|
|
const allProducts = Array.isArray(window._tsProducts) ? window._tsProducts : [];
|
|
|
|
createApp({
|
|
data() {
|
|
return {
|
|
products : allProducts,
|
|
store : store,
|
|
activeCategory : null,
|
|
activeSubCategory: null,
|
|
activeLeague : null,
|
|
};
|
|
},
|
|
computed: {
|
|
totalPublic() {
|
|
return this.products.length;
|
|
},
|
|
isLeagueStore() {
|
|
return this.store.url === 'hi-five-franchise-store';
|
|
},
|
|
// Build [ { name:'Basketball', count:N, subs:[{name:'Jersey',count:N},...] }, ... ]
|
|
categories() {
|
|
const map = {};
|
|
this.products.forEach(p => {
|
|
const { sport, item } = classify(p.name);
|
|
if (!map[sport]) map[sport] = {};
|
|
map[sport][item] = (map[sport][item] || 0) + 1;
|
|
});
|
|
return Object.entries(map)
|
|
.sort((a,b) => a[0].localeCompare(b[0]))
|
|
.map(([name, subs]) => ({
|
|
name,
|
|
count: Object.values(subs).reduce((a,b) => a+b, 0),
|
|
subs: Object.entries(subs)
|
|
.sort((a,b) => a[0].localeCompare(b[0]))
|
|
.map(([s, count]) => ({ name: s, count }))
|
|
.filter(s => s.name !== 'Other' || Object.keys(subs).length === 1),
|
|
}));
|
|
},
|
|
// Available leagues for the currently active category (+ optional sub)
|
|
// Only computed for hi-five-franchise-store
|
|
leagues() {
|
|
if (!this.isLeagueStore) return [];
|
|
const map = {};
|
|
this.products.forEach(p => {
|
|
const { sport, item, league } = classify(p.name);
|
|
if (!league) return;
|
|
if (this.activeCategory && sport !== this.activeCategory) return;
|
|
if (this.activeSubCategory && item !== this.activeSubCategory) return;
|
|
map[league] = (map[league] || 0) + 1;
|
|
});
|
|
return Object.entries(map)
|
|
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
.map(([name, count]) => ({ name, count }));
|
|
},
|
|
filtered() {
|
|
if (!this.activeCategory && !this.activeLeague) return this.products;
|
|
return this.products.filter(p => {
|
|
const { sport, item, league } = classify(p.name);
|
|
if (this.activeCategory && sport !== this.activeCategory) return false;
|
|
if (this.activeSubCategory && item !== this.activeSubCategory) return false;
|
|
if (this.isLeagueStore && this.activeLeague && league !== this.activeLeague) return false;
|
|
return true;
|
|
});
|
|
},
|
|
},
|
|
methods: {
|
|
selectCategory(cat) {
|
|
this.activeCategory = cat;
|
|
this.activeSubCategory = null;
|
|
this.activeLeague = null;
|
|
},
|
|
selectSub(cat, sub) {
|
|
this.activeCategory = cat;
|
|
this.activeSubCategory = sub;
|
|
this.activeLeague = null;
|
|
},
|
|
productUrl(p) {
|
|
return '/teamstore/' + store.url + '/product/' + p.url;
|
|
},
|
|
imgUrl(p) {
|
|
return store.minoBase + 'images/' + p.img;
|
|
},
|
|
},
|
|
}).mount('#ts-app');
|
|
})();
|
|
</script>
|
|
|
|
</div>{{-- /container --}}
|
|
@endsection
|