diff --git a/.gitignore b/.gitignore index 7c7745f..2781bdf 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,11 @@ /node_modules /public/hot /public/storage +/public/css +/public/js +/public/sitemap.xml +/public/main_sitemap.xml +/public/blog_sitemap.xml /storage/*.key /vendor .env @@ -14,3 +19,4 @@ Homestead.json Homestead.yaml npm-debug.log yarn-error.log +composer.lock diff --git a/app/Helpers/Test.php b/app/Helpers/Test.php new file mode 100644 index 0000000..52ad0a1 --- /dev/null +++ b/app/Helpers/Test.php @@ -0,0 +1,17 @@ +parse($text); +} + +function getCurrentMarket($request) +{ + return Market::find($request->session()->get('current_market_id')); +} + +function setCurrentMarket($request, $market) +{ + $request->session()->put('current_market_id', $market->id); +} + +function locationRoute(string $routeName, Market $market, Location $location): string +{ + return LocationRouter::build($routeName, $market, $location); +} diff --git a/app/Http/Controllers/Api/AvailabilityController.php b/app/Http/Controllers/Api/AvailabilityController.php new file mode 100644 index 0000000..cf0fcdd --- /dev/null +++ b/app/Http/Controllers/Api/AvailabilityController.php @@ -0,0 +1,147 @@ +transformer = $transformer; + } + + /** + * @var CalendarService + */ + public $calendarService; + + /** + * Get calendar service instance. + * @return CalendarService + */ + public function getCalendaService() + { + if (empty($this->calendarService)) { + $this->calendarService = app(CalendarService::class); + } + + return $this->calendarService; + } + + /** + * Find slot by slot by number. + * + * Includes viertual slots. + * + * @return Slot + */ + public function findByLocationSlug($locationSlug, $slotNumber) + { + $location = Location::where('slug', $locationSlug)->firstOrFail(); + $slot = $location->findOrGenerateSlot($slotNumber); + + return fractal($slot, $this->transformer) + ->respond(); + } + + /** + * Get hold. + * + * @param string $locationSlug + * @param string $slotNumber + * @return array + */ + public function getHold($locationSlug, $slotNumber) + { + $location = Location::where('slug', $locationSlug)->firstOrFail(); + $slot = $location->findOrGenerateSlot($slotNumber); + + return $slot->getHold(); + } + + /** + * Set slot hold. Throw error if lock already exists. + * + * @param Location $location + * @param string $slotNumber + * @return array + */ + public function setHold(Location $location, $slotNumber, CreateHold $request) + { + $slot = $location->findOrGenerateSlot($slotNumber); + + if ($slot->hasHold()) { + throw ValidationException::withMessages([ + 'slot_number' => 'The slot is already locked.', + ]); + } + + $slot->setHold($request->user()->id); + + return fractal($slot, $this->transformer) + ->includeHold() + ->respond(); + } + + /** + * Delete hold. + * + * @param string $locationSlug + * @param string $slotNumber + * @return array + */ + public function deleteHold($locationSlug, $slotNumber) + { + $location = Location::where('slug', $locationSlug)->firstOrFail(); + $slot = $location->findOrGenerateSlot($slotNumber); + + return $slot->releaseHold(); + } + + /** + * List slots by location slug. + * + * @return \Illuminate\Http\Response + */ + public function indexByLocationSlug($locationSlug, IndexAvailabilities $request) + { + $calendarService = $this->getCalendaService(); + $location = $request->getLocation(); + + $initialDate = $request->input('initial_date'); + $finalDate = $request->input('final_date'); + + $slots = $calendarService->getLocationSlotsForDateRange($location->id, $initialDate, $finalDate); + + $recurringSchedules = $calendarService->getLocationRecurringScheduleForDateRange($location->id, $initialDate, $finalDate); + $erasers = $calendarService->getLocationScheduleErasersForDateRange( + $location->id, + Carbon::parse($initialDate, $location->getPhpTzAttribute()), + Carbon::parse($finalDate ?? $initialDate, $location->getPhpTzAttribute())->addDays(1)->setTime(0, 0, 0), + ); + + $slots = $slots + ->applyRecurringSchedules($recurringSchedules, $initialDate, $finalDate) + ->applyFilters($request->filter) + ->removeConflicts() + ->applyErasers($erasers) + ->sortBy($request->input('sort', 'start_at')); + + return fractal($slots, $this->transformer) + ->respond(); + } +} diff --git a/app/Http/Controllers/Api/ThemesController.php b/app/Http/Controllers/Api/ThemesController.php new file mode 100644 index 0000000..5d8918c --- /dev/null +++ b/app/Http/Controllers/Api/ThemesController.php @@ -0,0 +1,38 @@ +transformer = $transformer; + } + + /** + * Display a listing of the resource. + * + * @param \App\Http\Requests\Theme\IndexThemes $request + * @return \Illuminate\Http\Response + */ + public function index(IndexThemes $request) + { + $themes = EscaperoomTheme::filter($request->filter) + ->paginate( + $request->getPageSize() + ); + + return fractal($themes, $this->transformer) + ->respond(); + } +} diff --git a/app/Http/Controllers/Web/Site/CompanyController.php b/app/Http/Controllers/Web/Site/CompanyController.php new file mode 100644 index 0000000..c288751 --- /dev/null +++ b/app/Http/Controllers/Web/Site/CompanyController.php @@ -0,0 +1,35 @@ +join('phones', 'phones.id', '=', 'locations.phone_id'); + + $image = Image::find(43)->url; + + return view('website.pages.company.company', [ + 'market' => $current, + 'locations' => $locations, + 'html' => null, // set to true if need to use html page instead of AMP + 'title' => 'About The Great Escape Room', + 'subtitle' => 'Voted #1 Escape Room across America - A truly innovative experience that will keep you coming back for more!', + 'cta' => true, + 'seotitle' => 'About The Great Escape Room', + 'seodescription' => 'Find out more about The Great Escape Room, a leader in the escape room industry with ' . $locations->count() . ' locations.', + 'ogtitle' => 'About The Great Escape Room', + 'ogdescription' => 'Find out more about The Great Escape Room, a leader in the escape room industry with ' . $locations->count() . ' locations.', + 'canonical' => route('company'), + 'image' => $image, + 'ogimage' => $image === null ? url('img/ogimage.jpg') : $image, + ]); + } +} diff --git a/app/Http/Controllers/Web/Site/MarketController.php b/app/Http/Controllers/Web/Site/MarketController.php new file mode 100644 index 0000000..838f8ff --- /dev/null +++ b/app/Http/Controllers/Web/Site/MarketController.php @@ -0,0 +1,98 @@ +segment(1))->first(); + if (is_null($market)) { + abort(404); + } + if (! is_null($request->segment(2))) { + return redirect()->to($market->path); + } + + setCurrentMarket($request, $market); + + $locations = $market->locations; + + // Get all rooms for those locations + $rooms = Room::whereIn('location_id', $locations->pluck('id')) + ->whereNull('closed_at') + ->orderByDesc('priority') + ->get(); + + $roomPriority = $rooms->pluck('priority', 'theme_id'); + $roomnotes = $rooms->filter->note->pluck('note', 'theme_id'); + $roomtitles = $rooms->filter->title->pluck('title', 'theme_id'); + $roomexcerpts = $rooms->filter->excerpt->pluck('excerpt', 'theme_id'); + $roomdescriptions = $rooms->filter->description->pluck('description', 'theme_id'); + + $comingsoon = $rooms->filter(function ($room) { + return $room->isComing(); + })->pluck('opened_at', 'theme_id'); + + // Get the themes, ordered by rooms->priority exclude closed themes and remove duplicates + $themes = EscaperoomTheme::whereIn('id', $rooms->pluck('theme_id')) + ->get() + ->sortBy(function ($theme) use ($roomPriority) { + return $roomPriority[$theme->id]; + }); + + $marketreviews = Review::where('is_displayable', true)->whereIn('location_id', $locations->pluck('id'))->orderByDesc('reviewed_at')->limit(6)->get(); + if ($marketreviews->count() <= 3) { + $marketreviews = null; + } + + $image = $market->image === null ? url('img/hero/tger.jpg') : $market->image->url; + + return view('website.markets.show', [ + 'market' => $market, + 'themes' => $themes, + 'availablelocations' => $this->availableLocations($themes, $rooms, $locations), + 'notes' => $roomnotes, + 'titles' => $roomtitles, + 'excerpts' => $roomexcerpts, + 'descriptions' => $roomdescriptions, + 'comingsoon' => $comingsoon, + 'reviews' => $marketreviews, + 'html' => null, // set to true if need to use html page instead of AMP + 'title' => $market->title, + 'subtitle' => 'Voted #1 Escape Room across America - A truly innovative experience that will keep you coming back for more!', + 'cta' => true, + 'seotitle' => $market->title, + 'seodescription' => $market->description, + 'ogtitle' => $market->title, + 'ogdescription' => $market->description, + 'canonical' => 'https://thegreatescaperoom.com'.$market->path, + 'image' => $image, + 'ogimage' => $market->ogimage === null ? $image : $market->ogimage->url, + ]); + } + + private function availableLocations($themes, $rooms, $locations) + { + // For each theme, return $themeId => [locations that have this theme] + return $themes->mapWithKeys(function ($theme) use ($rooms, $locations) { + $availablerooms = $rooms->filter(function ($room) use ($theme) { + return $room->theme_id === $theme->id; + }); + + return [ + $theme->id => $locations->filter(function ($location) use ($availablerooms) { + return $availablerooms->contains('location_id', $location->id); + }), + ]; + }); + } +} diff --git a/app/Http/Controllers/Web/Site/Pages/Booking/SlotsController.php b/app/Http/Controllers/Web/Site/Pages/Booking/SlotsController.php new file mode 100644 index 0000000..dbe0c81 --- /dev/null +++ b/app/Http/Controllers/Web/Site/Pages/Booking/SlotsController.php @@ -0,0 +1,91 @@ +segment(1) === 'company') { + return redirect()->to($current->bookings_path); + } + + $image = url('img/tger.jpg'); + + // Show the page in the company section of the site + if ($request->segment(1) === 'company') { + return view('website.pages.company.choose', [ + 'market' => $current, + 'html' => null, // set to true if need to use html page instead of AMP + 'title' => 'Book Online at The Great Escape Room', + 'subtitle' => 'Please select your location from the dropdown below:', + 'cta' => null, + 'link' => 'bookings', + 'seotitle' => 'Book Online at The Great Escape Room', + 'seodescription' => 'Book Online at The Great Escape Room, a leader in the escape room industry with 12 locations. Visit our website to learn more.', + 'ogtitle' => 'Book Online at The Great Escape Room', + 'ogdescription' => 'Book Online at The Great Escape Room, a leader in the escape room industry with 12 locations. Visit our website to learn more.', + 'canonical' => route('bookings'), + 'image' => $image, + 'ogimage' => $image === null ? url('img/ogimage.jpg') : $image, + ]); + } + + // Send to correct market if somehow they get to a URL with a different market than where the location belongs + if ($location && $market->id !== $location->market_id) { + return redirect()->to($location->bookings_path); + } + + // If there is only one location in the market, remove the trailing location name in the route/URL + if ($market->locations_count === 1 && $location) { + return redirect()->to($market->bookings_path); + } + + setCurrentMarket($request, $market); + + // In a multi-location market, ask the user to choose a location + if ($market->locations_count !== 1 && ! $location) { + return view('website.markets.select', [ + 'market' => $market, + 'html' => null, // set to true if need to use html page instead of AMP + 'title' => 'Book your game in '.$market->name, + 'subtitle' => 'Please select your '.$market->name.' location from the dropdown below:', + 'cta' => null, + 'link' => 'bookings', + 'seotitle' => 'Book Online at '.$market->name.' Escape Rooms', + 'seodescription' => $market->title.' has '.$market->rooms->count().' different escape rooms and offers private escape games for groups & parties. Book your escape room today!', + 'ogtitle' => 'Book Online at '.$market->name.' Escape Rooms', + 'ogdescription' => $market->title.' has '.$market->rooms->count().' different escape rooms and offers private escape games for groups & parties. Book your escape room today!', + 'canonical' => 'https://thegreatescaperoom.com'.$market->bookings_path, + 'image' => $image, + 'ogimage' => $image === null ? url('img/ogimage.jpg') : $image, + ]); + } + + // If end up here, then display the bookings page + if (! $location) { + $location = $market->locations->first(); + } + + return view('website.pages.booking.slots', [ + 'market' => $market, + 'location' => $location, + 'html' => true, + 'seotitle' => 'Book Online at '.$market->name.' Escape Rooms', + 'seodescription' => $market->title.' has '.$market->rooms->count().' different escape rooms and offers private escape games for groups & parties. Book your escape room today!', + 'ogtitle' => 'Book Online at '.$market->name.' Escape Rooms', + 'ogdescription' => $market->title.' has '.$market->rooms->count().' different escape rooms and offers private escape games for groups & parties. Book your escape room today!', + 'canonical' => 'https://thegreatescaperoom.com'.$location->bookings_path, + 'image' => $image, + 'ogimage' => $image === null ? url('img/ogimage.jpg') : $image, + ]); + } +} diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 30020a5..0d36725 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -33,6 +33,7 @@ class Kernel extends HttpKernel \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, + \Spatie\GoogleTagManager\GoogleTagManagerMiddleware::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, diff --git a/app/Http/Requests/ApiRequest.php b/app/Http/Requests/ApiRequest.php new file mode 100644 index 0000000..34f5f59 --- /dev/null +++ b/app/Http/Requests/ApiRequest.php @@ -0,0 +1,102 @@ +model)) { + $model = app($this->getModelClass()); + + $parameter = $this + ->route() + ->parameter( + Str::singular($model->getTable()) + ); + if (is_object($parameter) && $this->getModelClass() == get_class($parameter)) { + $model = $parameter; + } + $this->model = $model; + } + + return $this->model; + } + + /** + * Get base name of model class. + * + * @return string + */ + public function getModelClassBasename() + { + $baseName = class_basename($this->getModelClass()); + + return strtolower($baseName); + } + + /** + * Get fillable fields of model. + * + * @return array + */ + public function getFillable() + { + return $this->getModel()->getFillable(); + } + + /** + * Check if user is authorized to perform action. + * + * @param string $action + * @return bool + */ + public function authorizeAction($action) + { + $user = $this->user(); + $policy = Gate::getPolicyFor($this->getModel()); + + switch ($action) { + case 'viewAny': + case 'create': + return $user->can($action, $this->getModel()); + default: + return $user->can($action, $this->getModel()); + } + } + + /** + * Get pagination size. + * + * @return array + */ + public function getPageSize() + { + if ($this->has('page.size')) { + return $this->input('page.size'); + } + + return self::PAGE_SIZE; + } +} diff --git a/app/Http/Requests/Availability/CreateHold.php b/app/Http/Requests/Availability/CreateHold.php new file mode 100644 index 0000000..fc4b584 --- /dev/null +++ b/app/Http/Requests/Availability/CreateHold.php @@ -0,0 +1,30 @@ +user(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + // + ]; + } +} diff --git a/app/Http/Requests/Availability/IndexAvailabilities.php b/app/Http/Requests/Availability/IndexAvailabilities.php new file mode 100644 index 0000000..33747c8 --- /dev/null +++ b/app/Http/Requests/Availability/IndexAvailabilities.php @@ -0,0 +1,90 @@ +has('initial_date')) { + return Carbon::now(); + } + + return $this->getLocation()->toUtcDateTime($this->input('initial_date')); + } + + /** + * Get final date. + * + * @return Carbon + */ + public function getUtclFinalDate() + { + if (! $this->has('final_date')) { + return Carbon::now(); + } + + return $this->getLocation()->toUtcDateTime($this->input('final_date')); + } + + /** + * Get location. + * + * @return Carbon + */ + public function getLocation() + { + if (empty($this->location)) { + $this->location = Location::where('slug', $this->route()->parameter('locationSlug')) + ->firstOrFail(); + } + + return $this->location; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'initial_date' => [ + 'date', + ], + 'sort' => [ + 'in:slot_number,participants,room_id,rate_id,schedule_id,schedule_type,time,start_at,room_available_at,participants_available', + ], + 'final_date' => [ + 'date', + new DayRange($this->input('initial_date', now()->format('Y-m-d')), 7), + ], + ]; + } +} diff --git a/app/Http/Requests/Theme/IndexThemes.php b/app/Http/Requests/Theme/IndexThemes.php new file mode 100644 index 0000000..91971d3 --- /dev/null +++ b/app/Http/Requests/Theme/IndexThemes.php @@ -0,0 +1,41 @@ +orderBy('name')->get(); + }); + $navescapethemes = Cache::remember('allthemes', 3600, function () { + return EscaperoomTheme::where('scavenger_level', '<', 4)->orderBy('name')->get(); + }); + $navscavengerthemes = Cache::remember('allscavengerthemes', 3600, function () { + return EscaperoomTheme::where('scavenger_level', '>=', 4)->orderBy('name')->get(); + }); + + return $view->with('navmarkets', $navmarkets)->with('navescapethemes', $navescapethemes)->with('navscavengerthemes', $navscavengerthemes); + }); + + View::composer('website.partials.footer', function ($view) { + $allmarkets = Cache::remember('allmarkets', 3600, function () { + return Market::orderBy('state_id')->orderBy('name')->get(); + }); + $flmarkets = Cache::remember('flmarkets', 3600, function () { + return Market::join('states', 'states.id', '=', 'markets.state_id') + ->where('states.abbreviation', 'FL') + ->orderBy('markets.name') + ->get(); + }); + $midmarkets = Cache::remember('midmarkets', 3600, function () { + return Market::join('states', 'states.id', '=', 'markets.state_id') + ->where('states.abbreviation', ['MI', 'OH', 'IL']) + ->orderBy('markets.name') + ->get(); + }); + $nemarkets = Cache::remember('nemarkets', 3600, function () { + return Market::join('states', 'states.id', '=', 'markets.state_id') + ->where('states.abbreviation', ['NY', 'RI', 'DC', 'PA']) + ->orderBy('markets.name') + ->get(); + }); + $footerthemes = Cache::remember('footerthemes', 3600, function () { + return EscaperoomTheme::orderBy('name')->limit(7)->get(); + }); + + return $view->with('allmarkets', $allmarkets)->with('flmarkets', $flmarkets)->with('midmarkets', $midmarkets)->with('nemarkets', $nemarkets)->with('footerthemes', $footerthemes); + }); + + View::composer('website.pages.company.choose', function ($view) { + $locationslist = Cache::remember('locationslist', 3600, function () { + return Location::select('locations.*', 'locations.name as location_name', 'locations.slug as location_slug', 'markets.*', 'markets.name as market_name') + ->join('markets', 'markets.id', '=', 'locations.market_id') + ->join('pages', 'pages.id', '=', 'locations.page_id') + ->orderBy('markets.state_id') + ->orderBy('markets.title') + ->orderBy('locations.name')->get(); + }); + return $view->with('locationslist', $locationslist); + }); } } diff --git a/app/Rules/DayRange.php b/app/Rules/DayRange.php new file mode 100644 index 0000000..6fb91b0 --- /dev/null +++ b/app/Rules/DayRange.php @@ -0,0 +1,52 @@ +initialDate = Carbon::parse($initialDate); + $this->days = $days; + } + + /** + * Determine if the validation rule passes. + * + * @param string $attribute + * @param mixed $value + * @return bool + */ + public function passes($attribute, $value) + { + return $this->initialDate->diffInDays($value) < $this->days; + } + + /** + * Get the validation error message. + * + * @return string + */ + public function message() + { + return ':attribute must be maximum :value days from initial date.'; + } +} diff --git a/app/Services/Breakdown.php b/app/Services/Breakdown.php new file mode 100644 index 0000000..612285f --- /dev/null +++ b/app/Services/Breakdown.php @@ -0,0 +1,148 @@ +BlockTypes['{tag'] won't work.). + * + * The second array is a list of all functions that should be called when the character is found. + * + * Leave out the 'block' or 'inline' part of the function name, as it will be prepended automatically. + */ + public function __construct() + { + parent::__construct(); + + $this->BlockTypes['?'][] = 'FAQSection'; + } + + protected function blockFAQSection($line) + { + if (! preg_match('/^\?{3}/', $line['text'])) { + return; + } + + $block = [ + 'char' => $line['text'][0], + 'element' => [ + 'name' => 'amp-accordion', + 'handler' => 'elements', + 'attributes' => [ + 'layout' => 'container', + 'disable-session-states' => '', + 'class' => 'ampstart-dropdown', + ], + ], + ]; + + $block['section'] = [ + 'name' => 'section', + 'handler' => 'elements', + 'text' => [ + [ + 'name' => 'header', + 'attributes' => [ + 'class' => 'faq-header', + 'role' => 'heading', + 'aria-expanded' => 'false', + ], + 'handler' => 'text', + 'text' => null, + ], + [ + 'name' => 'div', + 'attributes' => [ + 'class' => 'faq-body', + ], + 'handler' => 'lines', + 'text' => [], + ], + ], + ]; + + $block['element']['text'][] = &$block['section']; + + return $block; + } + + /** + * Appending the word `continue` to the function name will cause this function to be + * called to process any following lines, until $block['complete'] is set to be 'true'. + */ + protected function blockFAQSectionContinue($line, $block) + { + // block is done + if (isset($block['complete'])) { + return; + } + + // A blank newline has occurred. + if (isset($block['interrupted'])) { + $block['section']['text'][1]['text'][] = ''; + unset($block['interrupted']); + } + + // Check for end of the block. + if (preg_match('/\?{3}/', $line['text'])) { + $block['complete'] = true; + + return $block; + } + + // store line text for further processing + if (empty($block['section']['text'][0]['text'])) { + $block['section']['text'][0]['text'] = '## '.$line['text']; + } else { + $block['section']['text'][1]['text'][] = $line['text']; + } + + return $block; + } + + protected function inlineImage($excerpt) + { + $image = parent::inlineImage($excerpt); + + if ($image === null) { + return; + } + + $src = $image['element']['attributes']['src']; + + // This could be done outside of our video list, but I prefer to have them in a database table. + if (substr($src, 0, 2) == 'v=') { + if (Video::where('name', substr($src, 2))->first()) { + $dbvideo = Video::where('name', substr($src, 2))->first(); + $image['element']['name'] = 'amp-youtube'; + $image['element']['attributes']['data-videoid'] = $dbvideo->name; + $image['element']['attributes']['height'] = '270'; + $image['element']['attributes']['width'] = '480'; + $image['element']['attributes']['src'] = null; + $image['element']['attributes']['alt'] = null; + $image['element']['attributes']['layout'] = 'responsive'; + } + } + + if (ctype_digit($src)) { + if (Image::find($src)) { + $dbimage = Image::find($src); + $image['element']['name'] = 'amp-img'; + $image['element']['attributes']['src'] = $dbimage->url; + $image['element']['attributes']['height'] = $dbimage->height; + $image['element']['attributes']['width'] = $dbimage->width; + $image['element']['attributes']['alt'] = $dbimage->description; + $image['element']['attributes']['layout'] = 'responsive'; + } + } + + return $image; + } +} diff --git a/app/Transformers/AvailabilitySlotTransformer.php b/app/Transformers/AvailabilitySlotTransformer.php new file mode 100644 index 0000000..199cf40 --- /dev/null +++ b/app/Transformers/AvailabilitySlotTransformer.php @@ -0,0 +1,100 @@ + $slot->slot_number, + 'room_id' => $slot->room_id, + 'rate_id' => $slot->rate_id, + 'schedule_id' => $slot->schedule_id, + 'schedule_type' => $slot->schedule_type, + 'date' => $slot->date->format('Y-m-d'), + 'time' => $slot->time, + 'start_at' => (string) $slot->start_at, + 'end_at' => (string) $slot->end_at, + 'room_available_at' => (string) $slot->room_available_at, + 'location_start' => (string) $slot->location_start, + 'location_end' => (string) $slot->location_end, + 'location_available' => (string) $slot->location_available, + 'participants' => $slot->participants, + 'participants_blocked' => $slot->participants_blocked, + 'participants_available' => $slot->participants_available, + 'has_hold' => $slot->hasHold(), + 'is_virtual' => true, + ]; + + if ($slot->id) { + $output['id'] = $slot->id; + $output['is_virtual'] = false; + } + + return $output; + } + + /** + * Include room. + * + * @return League\Fractal\ItemResource + */ + public function includeRoom(EscaperoomSlot $slot) + { + return $this->item($slot->room, new RoomTransformer()); + } + + /** + * Include hold. + * + * @return League\Fractal\ItemResource + */ + public function includeHold(EscaperoomSlot $slot) + { + if (! $hold = $slot->hold) { + return $this->null(); + } + + return $this->item($hold, new HoldTransformer()); + } + + /** + * Include rate. + * + * @return League\Fractal\ItemResource + */ + public function includeRate(EscaperoomSlot $slot) + { + return $this->item($slot->rate, new RateTransformer()); + } +} diff --git a/app/Transformers/LocationTransformer.php b/app/Transformers/LocationTransformer.php new file mode 100644 index 0000000..59d251f --- /dev/null +++ b/app/Transformers/LocationTransformer.php @@ -0,0 +1,38 @@ +toArray(); + } +} diff --git a/app/Transformers/RateTransformer.php b/app/Transformers/RateTransformer.php new file mode 100644 index 0000000..d6acf88 --- /dev/null +++ b/app/Transformers/RateTransformer.php @@ -0,0 +1,67 @@ + $rate->id, + 'slug' => $rate->slug, + 'name' => $rate->name, + 'public_1' => $rate->public_1, + 'public_2' => $rate->public_2, + 'public_3' => $rate->public_3, + 'public_4' => $rate->public_4, + 'public_5' => $rate->public_5, + 'public_6' => $rate->public_6, + 'public_7' => $rate->public_7, + 'public_8' => $rate->public_8, + 'public_9' => $rate->public_9, + 'public_10' => $rate->public_10, + 'private_1' => $rate->private_1, + 'private_2' => $rate->private_2, + 'private_3' => $rate->private_3, + 'private_4' => $rate->private_4, + 'private_5' => $rate->private_5, + 'private_6' => $rate->private_6, + 'private_7' => $rate->private_7, + 'private_8' => $rate->private_8, + 'private_9' => $rate->private_9, + 'private_10' => $rate->private_10, + 'private_11' => $rate->private_11, + 'private_12' => $rate->private_12, + 'private_13' => $rate->private_13, + 'private_14' => $rate->private_14, + 'private_15' => $rate->private_15, + 'private_16' => $rate->private_16, + ]; + } +} diff --git a/app/Transformers/RoomTransformer.php b/app/Transformers/RoomTransformer.php new file mode 100644 index 0000000..2c6a122 --- /dev/null +++ b/app/Transformers/RoomTransformer.php @@ -0,0 +1,79 @@ + $room->id, + 'location_id' => $room->location_id, + 'theme_id' => $room->theme_id, + 'rate_id' => $room->rate_id, + 'opened_at' => $room->opened_at, + 'closed_at' => $room->closed_at, + 'participants' => $room->participants, + 'participants_private' => $room->participants_private, + 'reset_time' => $room->reset_time, + 'occupied_time' => $room->occupied_time, + 'priority' => $room->priority, + 'note' => $room->note, + 'title' => $room->title, + 'excerpt' => $room->excerpt, + 'description' => $room->description, + 'image_id' => $room->image_id, + 'poster_image_id' => $room->poster_image_id, + 'icon_url' => $room->icon_url, + 'youtube' => $room->youtube, + 'pitch' => $room->pitch, + ]; + } + + /** + * Include theme. + * + * @return League\Fractal\ItemResource + */ + public function includeTheme(Room $room) + { + return $this->item($room->theme, new ThemeTransformer()); + } + + /** + * Include location. + * + * @return League\Fractal\ItemResource + */ + public function includeLocation(Room $room) + { + return $this->item($room->location, new LocationTransformer()); + } +} diff --git a/app/Transformers/ThemeTransformer.php b/app/Transformers/ThemeTransformer.php new file mode 100644 index 0000000..9af25f5 --- /dev/null +++ b/app/Transformers/ThemeTransformer.php @@ -0,0 +1,59 @@ + $theme->id, + 'slug' => $theme->slug, + 'name' => $theme->name, + 'title' => $theme->title, + 'excerpt' => $theme->excerpt, + 'description' => $theme->description, + 'synopsis' => $theme->synopsis, + 'story' => $theme->story, + 'info' => $theme->info, + 'duration' => $theme->duration, + 'occupied_time' => $theme->occupied_time, + 'scavenger_level' => $theme->scavenger_level, + 'puzzle_level' => $theme->puzzle_level, + 'escape_rate' => $theme->escape_rate, + 'image_id' => $theme->image_id, + 'video_id' => $theme->video_id, + 'poster_image_id' => $theme->poster_image_id, + 'icon_id' => $theme->icon_id, + 'icon_url' => $theme->icon_url, + 'youtube' => $theme->youtube, + 'pitch' => $theme->pitch, + ]; + } +} diff --git a/composer.json b/composer.json index 7477547..57e817c 100644 --- a/composer.json +++ b/composer.json @@ -6,24 +6,35 @@ "license": "MIT", "require": { "php": "^7.3|^8.0", + "drewroberts/blog": "^4.5.4", "fideloper/proxy": "^4.4.1", "fruitcake/laravel-cors": "^2.0.3", "guzzlehttp/guzzle": "^7.0.1", "laravel/framework": "^8.38", "laravel/nova": "^3.22", - "silvanite/nova-field-cloudinary": "^1.3", "laravel/tinker": "^2.6.1", + "silvanite/nova-field-cloudinary": "^1.3", + "spatie/laravel-googletagmanager": "^2.6", + "tipoff/authorization": "^2.10.0", + "tipoff/checkout": "^2.8.0", + "tipoff/discounts": "^2.2.1", + "tipoff/escape-room": "^2.4.0", + "tipoff/feedback": "^2.1", + "tipoff/fees": "^2.3.1", + "tipoff/forms": "^2.2.0", + "tipoff/locations": "^2.14.1", + "tipoff/notes": "^2.2.0", + "tipoff/products": "^2.2.2", + "tipoff/profiles": "^2.0.0", + "tipoff/seo": "^2.8.0", + "tipoff/statuses": "^2.2.1", + "tipoff/support": "^2.2.0", + "tipoff/taxes": "^2.2.1", + "tipoff/vouchers": "^2.4.0", + "tipoff/waivers": "^2.1.1", + "tipoff/reviews": "^2.2.1", "tipoff/addresses": "^2.9.1", - "tipoff/authorization": "^2.8.6", - "tipoff/checkout": "^2.7.2", - "tipoff/support": "^2.1.5", - "tipoff/seo": "^2.7.6", - "tipoff/notes": "^2.1.0", - "tipoff/forms": "^2.1.0", - "drewroberts/blog": "^4.5.4", - "tipoff/escape-room": "^2.3.4", - "tipoff/locations": "^2.12.0", - "tipoff/scheduler": "^2.0.1", + "tipoff/scheduler": "^2.0.1" }, "require-dev": { "facade/ignition": "^2.8.3", @@ -34,6 +45,10 @@ "phpunit/phpunit": "^9.3.3" }, "autoload": { + "files": [ + "app/Helpers/Website.php", + "app/Helpers/Test.php" + ], "psr-4": { "App\\": "app/", "Database\\Factories\\": "database/factories/", diff --git a/config/auth.php b/config/auth.php index 4e9cbaa..002ab7f 100644 --- a/config/auth.php +++ b/config/auth.php @@ -51,6 +51,12 @@ 'provider' => 'users', 'hash' => false, ], + + 'customer' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + ], /* diff --git a/config/googletagmanager.php b/config/googletagmanager.php new file mode 100644 index 0000000..c8b35ef --- /dev/null +++ b/config/googletagmanager.php @@ -0,0 +1,27 @@ + env('GOOGLE_TAG_MANAGER_ID', ''), + + /* + * Enable or disable script rendering. Useful for local development. + */ + 'enabled' => env('GOOGLE_TAG_MANAGER_ENABLED', true), + + /* + * If you want to use some macro's you 'll probably store them + * in a dedicated file. You can optionally define the path + * to that file here and we will load it for you. + */ + 'macroPath' => env('GOOGLE_TAG_MANAGER_MACRO_PATH', ''), + + /* + * The key under which data is saved to the session with flash. + */ + 'sessionKey' => env('GOOGLE_TAG_MANAGER_SESSION_KEY', '_googleTagManager'), + +]; diff --git a/mix-manifest.json b/mix-manifest.json new file mode 100644 index 0000000..eeaabe2 --- /dev/null +++ b/mix-manifest.json @@ -0,0 +1,16 @@ +{ + "/nova-components/Booking/dist/js/tool.js": "/nova-components/Booking/dist/js/tool.js", + "/nova-components/BookingCalendar/dist/js/tool.js": "/nova-components/BookingCalendar/dist/js/tool.js", + "/public/js/app.js": "/public/js/app.js", + "/public/js/booking.js": "/public/js/booking.js", + "/public/js/gifts.js": "/public/js/gifts.js", + "/public/js/waiver.js": "/public/js/waiver.js", + "/public/css/website.css": "/public/css/website.css", + "/public/css/feedback.css": "/public/css/feedback.css", + "/public/css/waiver.css": "/public/css/waiver.css", + "/public/css/booking.css": "/public/css/booking.css", + "/public/css/gifts.css": "/public/css/gifts.css", + "/nova-components/Booking/dist/css/tool.css": "/nova-components/Booking/dist/css/tool.css", + "/nova-components/BookingCalendar/dist/css/tool.css": "/nova-components/BookingCalendar/dist/css/tool.css", + "/public/css/app.css": "/public/css/app.css" +} diff --git a/package.json b/package.json index 00c6506..badad3e 100644 --- a/package.json +++ b/package.json @@ -2,17 +2,68 @@ "private": true, "scripts": { "dev": "npm run development", - "development": "mix", - "watch": "mix watch", - "watch-poll": "mix watch -- --watch-options-poll=1000", - "hot": "mix watch --hot", + "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", + "watch": "npm run production -- --watch", + "watch-poll": "npm run watch -- --watch-poll", + "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", "prod": "npm run production", - "production": "mix --production" + "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" }, "devDependencies": { + "eslint": "^7.5.0", + "eslint-config-standard": "^14.1.1", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.1", + "eslint-plugin-vue": "^6.2.2", + "husky": "^4.2.5", + "lint-staged": "^10.2.11" + }, + "dependencies": { + "@buddye/postcss-remove-important": "^1.0.3", + "@fortawesome/fontawesome-free": "^5.13.0", + "@fullcalendar/core": "^4.4.2", + "@fullcalendar/daygrid": "^4.4.2", + "@fullcalendar/resource-timegrid": "^4.4.2", + "@fullcalendar/resource-timeline": "^4.4.2", + "@fullcalendar/vue": "^4.4.2", + "@fullhuman/postcss-purgecss": "^2.3.0", + "@stripe/stripe-js": "^1.7.0", "axios": "^0.21", - "laravel-mix": "^6.0.6", + "bootstrap": "^4.5.0", + "cross-env": "^7.0.2", + "css-byebye": "^2.0.2", + "cssnano": "^4.1.10", + "icheck-bootstrap": "^3.0.1", + "jquery": "^3.5.1", + "laravel-mix": "^5.0.4", "lodash": "^4.17.19", - "postcss": "^8.1.14" + "lodash.sortby": "^4.7.0", + "moment": "^2.26.0", + "overlayscrollbars": "^1.12.0", + "popper.js": "^1.12", + "postcss": "^7.0.32", + "postcss-clear-empty-strings": "^1.0.0", + "postcss-discard-comments": "^4.0.2", + "postcss-loader": "^3.0.0", + "postcss-no-important": "^3.0.1", + "postcss-rm-imports": "^1.1.0", + "postcss-sanitize": "0.0.7", + "purgecss": "^2.3.0", + "resolve-url-loader": "^2.3.1", + "sass": "^1.26.8", + "sass-loader": "^8.0.0", + "signature_pad": "^3.0.0-beta.3", + "uuid": "^8.1.0", + "vue": "^2.5.17", + "vue-moment": "^4.1.0", + "vue-router": "^3.3.4", + "vue-signature-pad": "^2.0.2", + "vue-template-compiler": "^2.6.10", + "vue-the-mask": "^0.11.1", + "vuejs-datepicker": "^1.6.2", + "vuelidate": "^0.7.5", + "vuex": "^3.4.0" } } diff --git a/public/img/background/testimonial-lower-left-corner.svg b/public/img/background/testimonial-lower-left-corner.svg new file mode 100644 index 0000000..343a36a --- /dev/null +++ b/public/img/background/testimonial-lower-left-corner.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/background/testimonial-upper-right-corner.svg b/public/img/background/testimonial-upper-right-corner.svg new file mode 100644 index 0000000..43e7009 --- /dev/null +++ b/public/img/background/testimonial-upper-right-corner.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/background/tger-hero-bg.png b/public/img/background/tger-hero-bg.png new file mode 100644 index 0000000..b309e7c Binary files /dev/null and b/public/img/background/tger-hero-bg.png differ diff --git a/public/img/background/tger-purple-halftone.png b/public/img/background/tger-purple-halftone.png new file mode 100644 index 0000000..9ccf26f Binary files /dev/null and b/public/img/background/tger-purple-halftone.png differ diff --git a/public/img/background/tger-purple-halftone.svg b/public/img/background/tger-purple-halftone.svg new file mode 100644 index 0000000..e8e9884 --- /dev/null +++ b/public/img/background/tger-purple-halftone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/background/tger-testimonial-bg.svg b/public/img/background/tger-testimonial-bg.svg new file mode 100644 index 0000000..b946cfe --- /dev/null +++ b/public/img/background/tger-testimonial-bg.svg @@ -0,0 +1,1805 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/background/tger-yellow-halftone.png b/public/img/background/tger-yellow-halftone.png new file mode 100644 index 0000000..9c30e8d Binary files /dev/null and b/public/img/background/tger-yellow-halftone.png differ diff --git a/public/img/background/tger-yellow-halftone.svg b/public/img/background/tger-yellow-halftone.svg new file mode 100644 index 0000000..e83cfd5 --- /dev/null +++ b/public/img/background/tger-yellow-halftone.svg @@ -0,0 +1,19666 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/tger.jpg b/public/img/tger.jpg new file mode 100644 index 0000000..cd05303 Binary files /dev/null and b/public/img/tger.jpg differ diff --git a/public/mix-manifest.json b/public/mix-manifest.json new file mode 100644 index 0000000..5ddd485 --- /dev/null +++ b/public/mix-manifest.json @@ -0,0 +1,7 @@ +{ + "/js/app.js": "/js/app.js", + "/js/booking.js": "/js/booking.js", + "/css/website.css": "/css/website.css", + "/css/booking.css": "/css/booking.css", + "/css/app.css": "/css/app.css" +} diff --git a/resources/js/app.js b/resources/js/app.js index 40c55f6..cad5b8a 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -1 +1,11 @@ require('./bootstrap'); + +window.Vue = require('vue'); + +import moment from 'moment'; + +Vue.prototype.moment = moment; + +const app = new Vue({ + el: '#app', +}); diff --git a/resources/js/booking.js b/resources/js/booking.js new file mode 100644 index 0000000..d6900ad --- /dev/null +++ b/resources/js/booking.js @@ -0,0 +1,29 @@ +require('./bootstrap'); + +import Vue from 'vue'; +import VueRouter from 'vue-router'; +import moment from 'moment'; +import store from './booking/store'; +import './booking/filters'; + +Vue.use(VueRouter); + +Vue.prototype.moment = moment; +Vue.use(require('vue-moment')); +Vue.prototype.accessToken = process.env.MIX_TGER_ACCESS_TOKEN; +Vue.prototype.csrfToken = document.querySelector('meta[name="csrf-token"]').content; + +Vue.component('countdown-clock', require('./booking/components/CountdownClock').default); +Vue.component('games-list', require('./booking/components/GamesList').default); +Vue.component('purchase-form', require('./booking/components/PurchaseForm').default); +Vue.component('deduction-code-form', require('./booking/components/DeductionCodeForm').default); + +const router = new VueRouter({ + mode: 'history', +}); + +new Vue({ + el: '#app', + store, + router, +}); diff --git a/resources/js/booking/components/CountdownClock.vue b/resources/js/booking/components/CountdownClock.vue new file mode 100644 index 0000000..6a40cd1 --- /dev/null +++ b/resources/js/booking/components/CountdownClock.vue @@ -0,0 +1,94 @@ + + + diff --git a/resources/js/booking/components/DeductionCodeForm.vue b/resources/js/booking/components/DeductionCodeForm.vue new file mode 100644 index 0000000..e629170 --- /dev/null +++ b/resources/js/booking/components/DeductionCodeForm.vue @@ -0,0 +1,57 @@ + + + diff --git a/resources/js/booking/components/ErrorMessage.vue b/resources/js/booking/components/ErrorMessage.vue new file mode 100644 index 0000000..bca916b --- /dev/null +++ b/resources/js/booking/components/ErrorMessage.vue @@ -0,0 +1,38 @@ + + + diff --git a/resources/js/booking/components/GameItem.vue b/resources/js/booking/components/GameItem.vue new file mode 100644 index 0000000..e01e024 --- /dev/null +++ b/resources/js/booking/components/GameItem.vue @@ -0,0 +1,254 @@ +