profileShare

rasmusjy / splitapp-frontend-vue

Read-only snapshot

No repository description.

main default branch 96 files Expires Sep 13, 2026, 9:06 AM
CreateView.vue 5,652 bytes
1 <script setup lang="ts">
2 import { ref } from 'vue'
3 import { useRouter, useRoute } from 'vue-router'
4 import { useI18n } from 'vue-i18n'
5 import WishlistService from '@/services/WishlistService'
6
7 const router = useRouter()
8 const route = useRoute()
9 const { t } = useI18n()
10
11 const tripId = route.params.tripId as string
12
13 const title = ref('')
14 const description = ref('')
15 const category = ref('Place')
16 const priority = ref('NiceToHave')
17 const estimatedCost = ref<number | null>(null)
18 const url = ref('')
19 const location = ref('')
20 const errors = ref<string[]>([])
21 const isSaving = ref(false)
22
23 async function handleSubmit() {
24 errors.value = []
25 isSaving.value = true
26
27 const result = await WishlistService.create({
28 tripId,
29 title: title.value,
30 description: description.value || null,
31 category: category.value,
32 priority: priority.value,
33 estimatedCost: estimatedCost.value,
34 url: url.value || null,
35 location: location.value || null,
36 })
37
38 if (result.errors) {
39 errors.value = result.errors
40 } else {
41 router.push({ name: 'WishlistIndex', params: { tripId } })
42 }
43
44 isSaving.value = false
45 }
46 </script>
47
48 <template>
49 <div class="row justify-content-center">
50 <div class="col-md-8 col-lg-6">
51 <h4 class="mb-4" style="color: var(--sa-gray-900)">
52 <i class="bi bi-plus-circle me-2" style="color: var(--sa-accent)"></i>{{ t('wishlist.create.title') }}
53 </h4>
54
55 <!-- Error Display -->
56 <div v-if="errors.length" class="sa-card-static sa-card-accent sa-card-accent-danger mb-4">
57 <div class="sa-card-body">
58 <div class="d-flex align-items-center mb-1">
59 <i class="bi bi-exclamation-triangle-fill me-2" style="color: var(--sa-danger)"></i>
60 <strong style="color: var(--sa-danger)">{{ t('wishlist.create.pleaseFix') }}</strong>
61 </div>
62 <div v-for="err in errors" :key="err" style="font-size: 0.875rem; color: var(--sa-gray-600)">
63 {{ err }}
64 </div>
65 </div>
66 </div>
67
68 <div class="sa-card-static">
69 <div class="sa-card-body">
70 <form @submit.prevent="handleSubmit">
71 <div class="mb-3">
72 <label for="title" class="form-label">{{ t('wishlist.create.itemTitle') }}</label>
73 <input id="title" v-model="title" type="text" class="form-control" required :placeholder="t('wishlist.create.titlePlaceholder')" />
74 </div>
75
76 <div class="mb-3">
77 <label for="description" class="form-label">{{ t('wishlist.create.description') }}</label>
78 <textarea id="description" v-model="description" class="form-control" rows="3" :placeholder="t('wishlist.create.descriptionPlaceholder')"></textarea>
79 </div>
80
81 <div class="row mb-3">
82 <div class="col-6">
83 <label for="category" class="form-label">{{ t('wishlist.create.category') }}</label>
84 <select id="category" v-model="category" class="form-select">
85 <option value="Place">{{ t('wishlist.category.Place') }}</option>
86 <option value="Activity">{{ t('wishlist.category.Activity') }}</option>
87 <option value="Restaurant">{{ t('wishlist.category.Restaurant') }}</option>
88 <option value="Other">{{ t('wishlist.category.Other') }}</option>
89 </select>
90 </div>
91 <div class="col-6">
92 <label for="priority" class="form-label">{{ t('wishlist.create.priority') }}</label>
93 <select id="priority" v-model="priority" class="form-select">
94 <option value="MustDo">{{ t('wishlist.priority.MustDo') }}</option>
95 <option value="NiceToHave">{{ t('wishlist.priority.NiceToHave') }}</option>
96 <option value="Optional">{{ t('wishlist.priority.Optional') }}</option>
97 </select>
98 </div>
99 </div>
100
101 <div class="mb-3">
102 <label for="estimatedCost" class="form-label">{{ t('wishlist.create.estimatedCost') }}</label>
103 <input
104 id="estimatedCost"
105 v-model.number="estimatedCost"
106 type="number"
107 step="0.01"
108 min="0"
109 class="form-control"
110 placeholder="0.00"
111 />
112 </div>
113
114 <div class="mb-3">
115 <label for="url" class="form-label">{{ t('wishlist.create.url') }}</label>
116 <input id="url" v-model="url" type="url" class="form-control" placeholder="https://..." />
117 </div>
118
119 <div class="mb-4">
120 <label for="location" class="form-label">{{ t('wishlist.create.location') }}</label>
121 <input id="location" v-model="location" type="text" class="form-control" :placeholder="t('wishlist.create.locationPlaceholder')" />
122 </div>
123
124 <div class="d-flex gap-2 justify-content-end">
125 <button
126 type="button"
127 class="sa-btn sa-btn-ghost"
128 @click="router.push({ name: 'WishlistIndex', params: { tripId } })"
129 >
130 {{ t('common.cancel') }}
131 </button>
132 <button
133 type="submit"
134 class="sa-btn sa-btn-primary"
135 :class="{ 'sa-btn-loading': isSaving }"
136 :disabled="isSaving"
137 >
138 {{ isSaving ? t('wishlist.create.saving') : t('wishlist.create.addItem') }}
139 </button>
140 </div>
141 </form>
142 </div>
143 </div>
144 </div>
145 </div>
146 </template>
147