Added About Page
This commit is contained in:
@@ -15,9 +15,15 @@ class Tour extends Model
|
|||||||
return $this->belongsToMany(Country::class, 'tour_countries', 'tour_id', 'country_id');
|
return $this->belongsToMany(Country::class, 'tour_countries', 'tour_id', 'country_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function tour_days()
|
||||||
|
{
|
||||||
|
return $this->hasMany(TourDay::class);
|
||||||
|
}
|
||||||
|
|
||||||
public static function featuredTours(){
|
public static function featuredTours(){
|
||||||
return Tour::whereHas('countries.continent')
|
return Tour::whereHas('countries.continent')
|
||||||
->with('countries.continent')
|
->with('countries.continent')
|
||||||
|
->with('tour_days')
|
||||||
->inRandomOrder()
|
->inRandomOrder()
|
||||||
->limit(4)
|
->limit(4)
|
||||||
->get();
|
->get();
|
||||||
|
|||||||
26
app/Models/TourDay.php
Normal file
26
app/Models/TourDay.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class TourDay extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'tour_days';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'tour_id',
|
||||||
|
'description',
|
||||||
|
'content',
|
||||||
|
'image',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Relationships
|
||||||
|
public function tour(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Tour::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
database/factories/TourDayFactory.php
Normal file
22
database/factories/TourDayFactory.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\Tour;
|
||||||
|
use App\Models\TourDay;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
class TourDayFactory extends Factory
|
||||||
|
{
|
||||||
|
protected $model = TourDay::class;
|
||||||
|
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'tour_id' => Tour::whereInternalName('hebei_harmony')->first()->id,
|
||||||
|
'description' => $this->faker->sentence(),
|
||||||
|
'content' => $this->faker->paragraphs(3, true),
|
||||||
|
'image' => $this->faker->imageUrl(800, 600, 'travel', true, 'Tour Day'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('tour_days', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('tour_id')
|
||||||
|
->constrained('tours')
|
||||||
|
->onDelete('cascade');
|
||||||
|
$table->string('description')->nullable();
|
||||||
|
$table->text('content')->nullable();
|
||||||
|
$table->string('image')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('tour_days');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\TourDay;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
@@ -13,7 +14,7 @@ class DatabaseSeeder extends Seeder
|
|||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
// User::factory(10)->create();
|
User::factory(10)->create();
|
||||||
$this
|
$this
|
||||||
->call(ContinentSeeder::class)
|
->call(ContinentSeeder::class)
|
||||||
->call(CountrySeeder::class)
|
->call(CountrySeeder::class)
|
||||||
@@ -21,6 +22,8 @@ class DatabaseSeeder extends Seeder
|
|||||||
->call(TourCountrySeeder::class)
|
->call(TourCountrySeeder::class)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
TourDay::factory()->count(5)->create();
|
||||||
|
|
||||||
User::factory()->create([
|
User::factory()->create([
|
||||||
'name' => 'Test User',
|
'name' => 'Test User',
|
||||||
'email' => 'test@example.com',
|
'email' => 'test@example.com',
|
||||||
|
|||||||
16
resources/js/components/dredgy/ButtonLink.vue
Normal file
16
resources/js/components/dredgy/ButtonLink.vue
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import {Link} from "@inertiajs/vue3";
|
||||||
|
defineProps({
|
||||||
|
href: String,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Link :href="href" style="display:block;width:100%;height:100%" >
|
||||||
|
<slot/>
|
||||||
|
</Link>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
@@ -3,6 +3,8 @@ import {Tour} from "@/types";
|
|||||||
|
|
||||||
import { defineProps } from 'vue'
|
import { defineProps } from 'vue'
|
||||||
import EdgyButton from "@/components/dredgy/EdgyButton.vue";
|
import EdgyButton from "@/components/dredgy/EdgyButton.vue";
|
||||||
|
import {Link} from "@inertiajs/vue3";
|
||||||
|
import ButtonLink from "@/components/dredgy/ButtonLink.vue";
|
||||||
const formatPrice = (price: number) => {
|
const formatPrice = (price: number) => {
|
||||||
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(price)
|
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(price)
|
||||||
}
|
}
|
||||||
@@ -33,12 +35,12 @@ const props = defineProps<{
|
|||||||
<h3 class="tour-title">{{tour.name}}</h3>
|
<h3 class="tour-title">{{tour.name}}</h3>
|
||||||
<p class="tour-description" v-if="tour.short_description">{{tour.short_description}}</p>
|
<p class="tour-description" v-if="tour.short_description">{{tour.short_description}}</p>
|
||||||
<div class="tour-details">
|
<div class="tour-details">
|
||||||
<div class="tour-detail">
|
<div v-if="tour.tour_days?.length" class="tour-detail">
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<circle cx="12" cy="12" r="10"></circle>
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
<polyline points="12,6 12,12 16,14"></polyline>
|
<polyline points="12,6 12,12 16,14"></polyline>
|
||||||
</svg>
|
</svg>
|
||||||
{{tour.length}} Days
|
<span>{{ tour.tour_days?.length }} Days</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tour-detail">
|
<div class="tour-detail">
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
@@ -50,7 +52,9 @@ const props = defineProps<{
|
|||||||
Maximum 6
|
Maximum 6
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<EdgyButton classes="btn-primary btn-full">View Details</EdgyButton>
|
<EdgyButton classes="btn-primary btn-full">
|
||||||
|
<ButtonLink :href="'/adventures/'+tour.internal_name">Details</ButtonLink>
|
||||||
|
</EdgyButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -33,9 +33,9 @@
|
|||||||
<p>Dr Edgy was founded by two close friends who met travelling in North Korea. Both of us love adventure travel with a bit of luxury. One of us is even an actual doctor.</p>
|
<p>Dr Edgy was founded by two close friends who met travelling in North Korea. Both of us love adventure travel with a bit of luxury. One of us is even an actual doctor.</p>
|
||||||
<p>You are in safe hands.</p>
|
<p>You are in safe hands.</p>
|
||||||
<EdgyButton classes="btn-primary">
|
<EdgyButton classes="btn-primary">
|
||||||
<Link href="/about">
|
<ButtonLink href="/about">
|
||||||
GET TO KNOW US
|
GET TO KNOW US
|
||||||
</Link>
|
</ButtonLink>
|
||||||
</EdgyButton>
|
</EdgyButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -149,7 +149,7 @@ import { ref } from 'vue'
|
|||||||
import EdgyButton from "@/components/dredgy/EdgyButton.vue";
|
import EdgyButton from "@/components/dredgy/EdgyButton.vue";
|
||||||
import SectionContainer from "@/components/dredgy/SectionContainer.vue";
|
import SectionContainer from "@/components/dredgy/SectionContainer.vue";
|
||||||
import SectionTitle from "@/components/dredgy/SectionTitle.vue";
|
import SectionTitle from "@/components/dredgy/SectionTitle.vue";
|
||||||
import {Link} from "@inertiajs/vue3";
|
import ButtonLink from "@/components/dredgy/ButtonLink.vue";
|
||||||
|
|
||||||
const isVisible = ref(false)
|
const isVisible = ref(false)
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ defineOptions({
|
|||||||
or a punchy day tour, we’ll keep it flexible, intimate, and full of good stories.
|
or a punchy day tour, we’ll keep it flexible, intimate, and full of good stories.
|
||||||
</p>
|
</p>
|
||||||
</Hero>
|
</Hero>
|
||||||
|
|
||||||
<div class="about-decorations">
|
<div class="about-decorations">
|
||||||
<div class="about-decoration about-decoration-1"></div>
|
<div class="about-decoration about-decoration-1"></div>
|
||||||
<div class="about-decoration about-decoration-2"></div>
|
<div class="about-decoration about-decoration-2"></div>
|
||||||
@@ -36,6 +37,7 @@ defineOptions({
|
|||||||
|
|
||||||
<!-- Why Choose Dr Edgy -->
|
<!-- Why Choose Dr Edgy -->
|
||||||
<SectionContainer class="section-block">
|
<SectionContainer class="section-block">
|
||||||
|
<br/><br/>
|
||||||
<div v-show-on-intersect="'fade-up'" class="about-content">
|
<div v-show-on-intersect="'fade-up'" class="about-content">
|
||||||
<SectionTitle
|
<SectionTitle
|
||||||
title="Why"
|
title="Why"
|
||||||
|
|||||||
25
resources/js/pages/TourNavigator.vue
Normal file
25
resources/js/pages/TourNavigator.vue
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {Tour} from "@/types";
|
||||||
|
import {usePage} from "@inertiajs/vue3";
|
||||||
|
import AppLayout from "@/layouts/AppLayout.vue";
|
||||||
|
|
||||||
|
interface Properties {
|
||||||
|
tour: Tour
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tour } = usePage().props as unknown as Properties
|
||||||
|
defineOptions({
|
||||||
|
layout: AppLayout
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section style="padding-top:20dvh;height: 100dvh">
|
||||||
|
{{tour.short_description}}
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
19
resources/js/types/index.d.ts
vendored
19
resources/js/types/index.d.ts
vendored
@@ -53,6 +53,20 @@ export interface Country {
|
|||||||
continent: Continent;
|
continent: Continent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
'tour_id',
|
||||||
|
'description',
|
||||||
|
'content',
|
||||||
|
'image',
|
||||||
|
*/
|
||||||
|
export interface TourDay {
|
||||||
|
id: number
|
||||||
|
tour_id: number
|
||||||
|
description: string
|
||||||
|
content: string
|
||||||
|
image: string | null
|
||||||
|
}
|
||||||
|
|
||||||
export interface Tour {
|
export interface Tour {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
@@ -61,5 +75,8 @@ export interface Tour {
|
|||||||
price: number
|
price: number
|
||||||
level: string
|
level: string
|
||||||
short_description: string
|
short_description: string
|
||||||
countries: ?Country[]
|
countries: Country[] | null
|
||||||
|
tour_days: TourDay[] | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,5 +15,11 @@ Route::get('/about', function () {
|
|||||||
return Inertia::render('AboutUs');
|
return Inertia::render('AboutUs');
|
||||||
})->name('about');
|
})->name('about');
|
||||||
|
|
||||||
|
Route::get('/adventures/{tour}', function ($tour) {
|
||||||
|
return Inertia::render('TourNavigator',[
|
||||||
|
'tour' => Tour::where('internal_name', $tour)->with('countries.continent')->first(),
|
||||||
|
]);
|
||||||
|
})->name('tour');
|
||||||
|
|
||||||
require __DIR__.'/settings.php';
|
require __DIR__.'/settings.php';
|
||||||
require __DIR__.'/auth.php';
|
require __DIR__.'/auth.php';
|
||||||
|
|||||||
Reference in New Issue
Block a user