Fix login bug. Improve reservations
This commit is contained in:
@@ -21,7 +21,8 @@
|
||||
"file": "^0.2.2",
|
||||
"pinia": "^2.1.7",
|
||||
"vue": "3",
|
||||
"vue-router": "4"
|
||||
"vue-router": "4",
|
||||
"vue3-google-login": "^2.0.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@quasar/app-vite": "^1.9.1",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { boot } from 'quasar/wrappers';
|
||||
import { Client, Account, Databases, Functions, ID } from 'appwrite';
|
||||
import {
|
||||
Client,
|
||||
Account,
|
||||
Databases,
|
||||
Functions,
|
||||
ID,
|
||||
AppwriteException,
|
||||
} from 'appwrite';
|
||||
import { useAuthStore } from 'src/stores/auth';
|
||||
import { Dialog, Notify } from 'quasar';
|
||||
import type { Router } from 'vue-router';
|
||||
@@ -90,7 +97,7 @@ async function logout() {
|
||||
});
|
||||
}
|
||||
|
||||
function login(email: string, password: string) {
|
||||
async function login(email: string, password: string) {
|
||||
const notification = Notify.create({
|
||||
type: 'primary',
|
||||
position: 'top',
|
||||
@@ -100,31 +107,31 @@ function login(email: string, password: string) {
|
||||
group: false,
|
||||
});
|
||||
const authStore = useAuthStore();
|
||||
authStore
|
||||
.login(email, password)
|
||||
.then(() => {
|
||||
notification({
|
||||
type: 'positive',
|
||||
message: 'Logged in!',
|
||||
timeout: 2000,
|
||||
spinner: false,
|
||||
icon: 'check_circle',
|
||||
});
|
||||
console.log('Redirecting to index page');
|
||||
appRouter.replace({ name: 'index' });
|
||||
})
|
||||
.catch(function (reason: Error) {
|
||||
notification({
|
||||
type: 'negative',
|
||||
message: 'Login failed.',
|
||||
timeout: 1,
|
||||
});
|
||||
try {
|
||||
await authStore.login(email, password);
|
||||
notification({
|
||||
type: 'positive',
|
||||
message: 'Logged in!',
|
||||
timeout: 2000,
|
||||
spinner: false,
|
||||
icon: 'check_circle',
|
||||
});
|
||||
console.log('Redirecting to index page');
|
||||
appRouter.replace({ name: 'index' });
|
||||
} catch (error: unknown) {
|
||||
notification({
|
||||
type: 'negative',
|
||||
message: 'Login failed.',
|
||||
timeout: 2000,
|
||||
});
|
||||
if (error instanceof AppwriteException) {
|
||||
Dialog.create({
|
||||
title: 'Login Error!',
|
||||
message: reason.message,
|
||||
message: error.message,
|
||||
persistent: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
export {
|
||||
client,
|
||||
|
||||
@@ -52,7 +52,8 @@
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ getUserName(reservation.user) || 'loading...' }}
|
||||
{{ getUserName(reservation.user) || 'loading...' }}<br />
|
||||
{{ reservation.reason }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
filled
|
||||
></q-input>
|
||||
<q-btn
|
||||
type="submit"
|
||||
@click="login(email, password)"
|
||||
type="button"
|
||||
@click="doLogin"
|
||||
label="Login"
|
||||
color="primary"
|
||||
></q-btn>
|
||||
@@ -44,7 +44,7 @@
|
||||
></q-btn> -->
|
||||
</q-form>
|
||||
</q-card-section>
|
||||
<q-card-section><GoogleOauthComponent /></q-card-section>
|
||||
<!-- <q-card-section><GoogleOauthComponent /></q-card-section> -->
|
||||
</q-card>
|
||||
</q-page>
|
||||
</q-page-container>
|
||||
@@ -69,8 +69,12 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { login } from 'boot/appwrite';
|
||||
import GoogleOauthComponent from 'src/components/GoogleOauthComponent.vue';
|
||||
// import GoogleOauthComponent from 'src/components/GoogleOauthComponent.vue';
|
||||
|
||||
const email = ref('');
|
||||
const password = ref('');
|
||||
|
||||
const doLogin = async () => {
|
||||
login(email.value, password.value);
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<q-page>
|
||||
<q-list>
|
||||
<q-form @submit="onSubmit" @reset="onReset" class="q-gutter-sm">
|
||||
<q-form @reset="onReset" class="q-gutter-sm">
|
||||
<q-item>
|
||||
<q-item-section :avatar="true">
|
||||
<q-icon name="person"
|
||||
@@ -45,52 +45,41 @@
|
||||
</li>
|
||||
</ol>
|
||||
</q-banner>
|
||||
<!-- <q-card-section>
|
||||
<q-card-section>
|
||||
<q-btn
|
||||
color="primary"
|
||||
class="full-width"
|
||||
icon="keyboard_arrow_down"
|
||||
icon-right="keyboard_arrow_down"
|
||||
label="Next: Crew & Passengers"
|
||||
label="Next: Booking Details"
|
||||
@click="resourceView = false"
|
||||
/></q-card-section> -->
|
||||
/></q-card-section>
|
||||
</q-expansion-item>
|
||||
<!-- <q-expansion-item
|
||||
<q-expansion-item
|
||||
expand-separator
|
||||
icon="people"
|
||||
label="Crew and Passengers"
|
||||
label="Booking Details"
|
||||
default-opened
|
||||
><q-banner v-if="bookingForm.boat"
|
||||
>Passengers:
|
||||
{{ bookingForm.members.length + bookingForm.guests.length }} /
|
||||
{{ bookingForm.boat.maxPassengers }}</q-banner
|
||||
>
|
||||
<q-item
|
||||
class="q-my-sm"
|
||||
v-for="passenger in [...bookingForm.members, ...bookingForm.guests]"
|
||||
:key="passenger.name"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-avatar color="primary" text-color="white" size="sm">
|
||||
{{
|
||||
passenger.name
|
||||
.split(' ')
|
||||
.map((i) => i.charAt(0))
|
||||
.join('')
|
||||
.toUpperCase()
|
||||
}}
|
||||
</q-avatar>
|
||||
</q-item-section>
|
||||
<q-item-section>{{ passenger.name }}</q-item-section>
|
||||
<q-item-section side>
|
||||
<q-btn color="negative" flat dense round icon="cancel" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-separator />
|
||||
</q-expansion-item> -->
|
||||
>
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<q-select
|
||||
filled
|
||||
v-model="bookingForm.reason"
|
||||
:options="reason_options"
|
||||
label="Reason for sail"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</q-expansion-item>
|
||||
|
||||
<q-item-section>
|
||||
<q-btn label="Submit" type="submit" color="primary" />
|
||||
<q-btn
|
||||
label="Submit"
|
||||
type="submit"
|
||||
@click="onSubmit"
|
||||
color="primary"
|
||||
/>
|
||||
</q-item-section> </q-form
|
||||
></q-list>
|
||||
</q-page>
|
||||
@@ -113,22 +102,25 @@ interface BookingForm {
|
||||
boat?: Boat;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
reason: string;
|
||||
members: { name: string }[];
|
||||
guests: { name: string }[];
|
||||
}
|
||||
|
||||
const reason_options = ['Open Sail', 'Private Sail', 'Racing', 'Other'];
|
||||
|
||||
const auth = useAuthStore();
|
||||
const dateFormat = 'MMM D, YYYY h:mm A';
|
||||
const resourceView = ref(true);
|
||||
const interval = ref<Interval>();
|
||||
const bookingForm = ref<BookingForm>({
|
||||
bookingId: getNewId(),
|
||||
name: auth.currentUser?.name,
|
||||
boat: <Boat | undefined>undefined,
|
||||
startDate: date.formatDate(new Date(), dateFormat),
|
||||
endDate: date.formatDate(new Date(), dateFormat),
|
||||
members: [{ name: 'Karen Henrikso' }, { name: "Rich O'hare" }],
|
||||
guests: [{ name: 'Bob Barker' }, { name: 'Taylor Swift' }],
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
reason: 'Open Sail',
|
||||
members: [],
|
||||
guests: [],
|
||||
});
|
||||
const router = useRouter();
|
||||
const reservationStore = useReservationStore();
|
||||
@@ -138,11 +130,8 @@ watch(interval, (new_interval) => {
|
||||
bookingForm.value.boat = useBoatStore().boats.find(
|
||||
(b) => b.$id === new_interval?.boatId
|
||||
);
|
||||
bookingForm.value.startDate = date.formatDate(
|
||||
new_interval?.start,
|
||||
dateFormat
|
||||
);
|
||||
bookingForm.value.endDate = date.formatDate(new_interval?.end, dateFormat);
|
||||
bookingForm.value.startDate = new_interval?.start;
|
||||
bookingForm.value.endDate = new_interval?.end;
|
||||
});
|
||||
|
||||
const onReset = () => {
|
||||
@@ -150,6 +139,7 @@ const onReset = () => {
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
console.log('SUBMIT!');
|
||||
const booking = bookingForm.value;
|
||||
if (
|
||||
!(booking.boat && booking.startDate && booking.endDate && auth.currentUser)
|
||||
@@ -163,9 +153,11 @@ const onSubmit = () => {
|
||||
end: booking.endDate,
|
||||
user: auth.currentUser.$id,
|
||||
status: 'confirmed',
|
||||
reason: booking.reason,
|
||||
};
|
||||
console.log(reservation);
|
||||
// TODO: Fix this. It will always look successful
|
||||
reservationStore.createReservation(reservation);
|
||||
reservationStore.createReservation(reservation); // Probably should pass the notify as a callback to the reservation creation.
|
||||
$q.notify({
|
||||
color: 'green-4',
|
||||
textColor: 'white',
|
||||
@@ -195,7 +187,9 @@ const bookingSummary = computed(() => {
|
||||
return bookingForm.value.boat &&
|
||||
bookingForm.value.startDate &&
|
||||
bookingForm.value.endDate
|
||||
? `${bookingForm.value.boat.name} @ ${bookingForm.value.startDate} for ${bookingDuration.value}`
|
||||
? `${bookingForm.value.boat.name} @ ${new Date(
|
||||
bookingForm.value.startDate
|
||||
).toLocaleString()} for ${bookingDuration.value}`
|
||||
: '';
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -36,12 +36,13 @@ export default route(function (/* { store, ssrContext } */) {
|
||||
});
|
||||
|
||||
Router.beforeEach((to) => {
|
||||
const auth = useAuthStore();
|
||||
const publicPages = routes
|
||||
.filter((route) => route.meta?.publicRoute)
|
||||
.map((r) => r.path);
|
||||
const authRequired = !publicPages.includes(to.path);
|
||||
|
||||
if (auth.currentUser) {
|
||||
return to.meta.accountRoute ? { name: 'index' } : true;
|
||||
} else {
|
||||
return to.name == 'login' ? true : { name: 'login' };
|
||||
if (authRequired && !useAuthStore().currentUser) {
|
||||
return '/login';
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ export const useReservationStore = defineStore('reservation', () => {
|
||||
reservation
|
||||
);
|
||||
reservations.value.set(response.$id, response as Reservation);
|
||||
console.info('Reservation booked: ', response);
|
||||
} catch (e) {
|
||||
console.error('Error creating Reservation: ' + e);
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ export function getSampleReservations(): Reservation[] {
|
||||
end: '10:00',
|
||||
boat: '66359729003825946ae1',
|
||||
status: 'confirmed',
|
||||
reason: 'Open Sail',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
@@ -79,6 +80,7 @@ export function getSampleReservations(): Reservation[] {
|
||||
end: '19:00',
|
||||
boat: '66359729003825946ae1',
|
||||
status: 'confirmed',
|
||||
reason: 'Open Sail',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
@@ -87,6 +89,7 @@ export function getSampleReservations(): Reservation[] {
|
||||
end: '13:00',
|
||||
boat: '663597030029b71c7a9b',
|
||||
status: 'tentative',
|
||||
reason: 'Open Sail',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
@@ -95,6 +98,7 @@ export function getSampleReservations(): Reservation[] {
|
||||
end: '13:00',
|
||||
boat: '663597030029b71c7a9b',
|
||||
status: 'pending',
|
||||
reason: 'Open Sail',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
@@ -103,6 +107,7 @@ export function getSampleReservations(): Reservation[] {
|
||||
end: '19:00',
|
||||
boat: '663596b9000235ffea55',
|
||||
status: 'confirmed',
|
||||
reason: 'Private Sail',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
@@ -110,6 +115,7 @@ export function getSampleReservations(): Reservation[] {
|
||||
start: '13:00',
|
||||
end: '16:00',
|
||||
boat: '663596b9000235ffea55',
|
||||
reason: 'Open Sail',
|
||||
},
|
||||
];
|
||||
const boatStore = useBoatStore();
|
||||
@@ -137,6 +143,7 @@ export function getSampleReservations(): Reservation[] {
|
||||
end: date.adjustDate(now, makeOpts(splitTime(entry.end))).toISOString(),
|
||||
resource: boat.$id,
|
||||
reservationDate: now,
|
||||
reason: entry.reason,
|
||||
status: entry.status as StatusTypes,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ export type Reservation = Partial<Models.Document> & {
|
||||
end: string;
|
||||
resource: string; // Boat ID
|
||||
status?: StatusTypes;
|
||||
reason: string;
|
||||
};
|
||||
|
||||
// 24 hrs in advance only 2 weekday, and 1 weekend slot
|
||||
|
||||
@@ -5278,6 +5278,11 @@ vue-tsc@^1.8.22:
|
||||
"@vue/language-core" "1.8.27"
|
||||
semver "^7.5.4"
|
||||
|
||||
vue3-google-login@^2.0.26:
|
||||
version "2.0.26"
|
||||
resolved "https://registry.yarnpkg.com/vue3-google-login/-/vue3-google-login-2.0.26.tgz#0e55dbb3c6cbb78872dee0de800624c749d07882"
|
||||
integrity sha512-BuTSIeSjINNHNPs+BDF4COnjWvff27IfCBDxK6JPRqvm57lF8iK4B3+zcG8ud6BXfZdyuiDlxletbEDgg4/RFA==
|
||||
|
||||
vue@3:
|
||||
version "3.4.25"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.25.tgz#e59d4ed36389647b52ff2fd7aa84bb6691f4205b"
|
||||
|
||||
Reference in New Issue
Block a user