Cleanup linting messages. Also, break some things

This commit is contained in:
2024-05-04 12:08:16 -04:00
parent c92f737612
commit fa4d83e42d
13 changed files with 196 additions and 174 deletions

4
appwrite.json Normal file
View File

@@ -0,0 +1,4 @@
{
"projectId": "65ede55a213134f2b688",
"projectName": ""
}

View File

@@ -24,7 +24,9 @@ const AppwriteIds = {
task: '65ee1cd5b550023fae4f', task: '65ee1cd5b550023fae4f',
taskTags: '65ee21d72d5c8007c34c', taskTags: '65ee21d72d5c8007c34c',
skillTags: '66072582a74d94a4bd01', skillTags: '66072582a74d94a4bd01',
boats: '66341910003e287cd71c', boat: '66341910003e287cd71c',
timeBlock: '66361869002883fb4c4b',
timeBlockTemplate: '66361f480007fdd639af',
}, },
}; };

View File

@@ -1,23 +1,26 @@
<template> <template>
<q-card v-for="boat in boats" :key="boat.id" flat class="mobile-card"> <div v-if="boats">
<q-card-section> <q-card v-for="boat in boats" :key="boat.id" flat class="mobile-card">
<q-img :src="boat.imgSrc" :fit="'scale-down'"> <q-card-section>
<div class="row absolute-top"> <q-img :src="boat.imgSrc" :fit="'scale-down'">
<div class="col text-h6 text-left">{{ boat.name }}</div> <div class="row absolute-top">
<div class="col text-right">{{ boat.class }}</div> <div class="col text-h6 text-left">{{ boat.name }}</div>
</div> <div class="col text-right">{{ boat.class }}</div>
</q-img> </div>
</q-card-section> </q-img>
</q-card-section>
<q-separator /> <q-separator />
<q-card-actions align="evenly"> <q-card-actions align="evenly">
<q-btn flat>Info</q-btn> <q-btn flat>Info</q-btn>
<q-btn flat>Book</q-btn> <q-btn flat>Book</q-btn>
<q-btn flat>Check-Out</q-btn> <q-btn flat>Check-Out</q-btn>
<q-btn flat>Check-In</q-btn> <q-btn flat>Check-In</q-btn>
</q-card-actions> </q-card-actions>
</q-card> </q-card>
</div>
<div v-else><q-card>Sorry, no boats to show you!</q-card></div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@@ -133,7 +133,7 @@
<q-separator /> <q-separator />
<q-list dense> <q-list dense>
<q-item <q-item
v-for="col in props.cols.filter((col) => col.name !== 'desc')" v-for="col in props.cols.filter((col:Boat) => col.name !== 'desc')"
:key="col.name" :key="col.name"
> >
<q-item-section> <q-item-section>
@@ -215,10 +215,8 @@
import { computed, defineProps, ref } from 'vue'; import { computed, defineProps, ref } from 'vue';
import { useTaskStore, Task, SkillTag, TaskTag } from 'src/stores/task'; import { useTaskStore, Task, SkillTag, TaskTag } from 'src/stores/task';
import { QTableProps, date, useQuasar } from 'quasar'; import { QTableProps, date, useQuasar } from 'quasar';
import { useBoatStore } from 'src/stores/boat'; import { Boat, useBoatStore } from 'src/stores/boat';
import { useRouter } from 'vue-router';
const router = useRouter();
const selected = ref([]); const selected = ref([]);
const loading = ref(false); // Placeholder const loading = ref(false); // Placeholder
const fabShow = ref(false); const fabShow = ref(false);
@@ -266,7 +264,7 @@ const columns = <QTableProps['columns']>[
align: 'left', align: 'left',
label: 'Boat', label: 'Boat',
field: (row) => field: (row) =>
useBoatStore().boats.find((boat) => boat.$id === row.boat)?.name, useBoatStore().boats.value.find((boat) => boat.$id === row.boat)?.name,
sortable: true, sortable: true,
}, },
{ {
@@ -301,44 +299,51 @@ const columns = <QTableProps['columns']>[
{ name: 'actions', align: 'center', label: 'Actions', field: '$id' }, { name: 'actions', align: 'center', label: 'Actions', field: '$id' },
]; ];
const props = defineProps<{ tasks: Task[] }>(); defineProps<{ tasks: Task[] }>();
const taskStore = useTaskStore(); const taskStore = useTaskStore();
const $q = useQuasar(); const $q = useQuasar();
const searchFilter = ref({ interface SearchObject {
title: string;
skillTags: SkillTag[];
taskTags: TaskTag[];
}
const searchFilter = ref<SearchObject>({
title: '', title: '',
skillTags: <SkillTag[]>[], skillTags: [],
taskTags: <TaskTag[]>[], taskTags: [],
}); });
const skillTagOptions = ref<SkillTag[]>(taskStore.skillTags); const skillTagOptions = ref<SkillTag[]>(taskStore.skillTags);
const taskTagOptions = ref<TaskTag[]>(taskStore.taskTags); const taskTagOptions = ref<TaskTag[]>(taskStore.taskTags);
function onRowClick(evt: Event, row: Task) { // function onRowClick(evt: Event, row: Task) {
router.push({ name: 'edit-task', params: { id: row.$id } }); // router.push({ name: 'edit-task', params: { id: row.$id } });
} // }
// TODO: Implement server side search // TODO: Implement server side search
const filterRows = computed( const filterRows = computed(
() => (rows: readonly Task[], terms: any, cols: any, cellValueFn: any) => { () => (rows: readonly Task[], terms: SearchObject) => {
let result = rows; return rows
result = rows.filter((row) => .filter((row) =>
terms.title terms.title
? row.title.toLowerCase().includes(terms.title.toLowerCase()) ? row.title.toLowerCase().includes(terms.title.toLowerCase())
: true : true
); )
result = result.filter((row) => .filter((row) =>
terms.skillTags && terms.skillTags.length > 0 terms.skillTags && terms.skillTags.length > 0
? row.required_skills.some((req_skill) => ? row.required_skills.some((req_skill) =>
terms.skillTags.map((t) => t.$id).includes(req_skill) terms.skillTags.map((t) => t.$id).includes(req_skill)
) )
: true : true
); )
result = result.filter((row) => .filter((row) =>
terms.taskTags && terms.taskTags.length > 0 terms.taskTags && terms.taskTags.length > 0
? row.tags.some((tag) => terms.taskTags.map((t) => t.$id).includes(tag)) ? row.tags.some((tag) =>
: true terms.taskTags.map((t) => t.$id).includes(tag)
); )
return result; : true
);
} }
); );

View File

@@ -11,5 +11,7 @@ import { ref } from 'vue';
import { useBoatStore } from 'src/stores/boat'; import { useBoatStore } from 'src/stores/boat';
import ToolbarComponent from 'src/components/ToolbarComponent.vue'; import ToolbarComponent from 'src/components/ToolbarComponent.vue';
const boatStore = useBoatStore();
boatStore.fetchBoats();
const boats = ref(useBoatStore().boats); const boats = ref(useBoatStore().boats);
</script> </script>

View File

@@ -8,32 +8,25 @@
<q-avatar icon="person" /> <q-avatar icon="person" />
</q-item-section> </q-item-section>
<q-item-section> <q-item-section>
Ricky Gervais {{ authStore.currentUser?.name }}
<q-item-label caption>Name</q-item-label> <q-item-label caption>Name</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item>
<q-item-section avatar>
<q-avatar icon="numbers" />
</q-item-section>
<q-item-section>
123456
<q-item-label caption>Member ID</q-item-label>
</q-item-section>
</q-item>
<q-separator /> <q-separator />
<q-item> <q-item>
<q-item-section> <q-item-section>
<q-item-label overline>Certifications</q-item-label> <q-item-label overline>Certifications</q-item-label>
<q-chip square icon="verified" color="green" text-color="white" <div>
>J/27</q-chip <q-chip square icon="verified" color="green" text-color="white"
> >J/27</q-chip
<q-chip square icon="verified" color="blue" text-color="white" >
>Capri25</q-chip <q-chip square icon="verified" color="blue" text-color="white"
> >Capri25</q-chip
<q-chip square icon="verified" color="red" text-color="white" >
>Night</q-chip <q-chip square icon="verified" color="grey-9" text-color="white"
> >Night</q-chip
>
</div>
</q-item-section> </q-item-section>
</q-item> </q-item>
</q-list> </q-list>
@@ -42,4 +35,7 @@
<script setup lang="ts"> <script setup lang="ts">
import ToolbarComponent from 'src/components/ToolbarComponent.vue'; import ToolbarComponent from 'src/components/ToolbarComponent.vue';
import { useAuthStore } from 'src/stores/auth';
const authStore = useAuthStore();
</script> </script>

View File

@@ -50,25 +50,17 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Reservation, useScheduleStore } from 'src/stores/schedule'; import { useScheduleStore } from 'src/stores/schedule';
import { Reservation } from 'src/stores/schedule.types';
import { ref } from 'vue'; import { ref } from 'vue';
const scheduleStore = useScheduleStore(); const scheduleStore = useScheduleStore();
import { import { TimestampOrNull, parseDate, today } from '@quasar/quasar-ui-qcalendar';
TimestampOrNull,
makeDateTime,
makeDate,
parseDate,
today,
} from '@quasar/quasar-ui-qcalendar';
import { QCalendarDay } from '@quasar/quasar-ui-qcalendar'; import { QCalendarDay } from '@quasar/quasar-ui-qcalendar';
import { date } from 'quasar'; import { date } from 'quasar';
import { Timestamp } from '@quasar/quasar-ui-qcalendar'; import { Timestamp } from '@quasar/quasar-ui-qcalendar';
const selectedDate = ref(today()); const selectedDate = ref(today());
// Use ref to get a reference to the QCalendarDay component
const calendarRef = ref(QCalendarDay);
// Method declarations // Method declarations
function slotStyle( function slotStyle(
@@ -93,16 +85,6 @@ function slotStyle(
function reservationEvents(timestamp: Timestamp) { function reservationEvents(timestamp: Timestamp) {
return scheduleStore.getBoatReservations(timestamp); return scheduleStore.getBoatReservations(timestamp);
} }
function onToday() {
calendarRef.value.moveToToday();
}
function onPrev() {
calendarRef.value.prev();
}
function onNext() {
calendarRef.value.next();
}
function onMoved(data) { function onMoved(data) {
console.log('onMoved', data); console.log('onMoved', data);
} }

View File

@@ -1,8 +1,11 @@
import { Models } from 'appwrite';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { AppwriteIds, databases } from 'src/boot/appwrite';
import { computed, ref } from 'vue';
// const boatSource = null; // const boatSource = null;
export interface Boat { export interface Boat extends Models.Document {
$id: string; $id: string;
name: string; name: string;
displayName?: string; displayName?: string;
@@ -21,81 +24,27 @@ export interface Boat {
}[]; }[];
} }
const getSampleData = () => [ export const useBoatStore = defineStore('boat', () => {
{ const boatData = ref<Boat[]>([]);
$id: '1',
name: 'ProjectX',
displayName: 'PX',
class: 'J/27',
year: 1981,
imgSrc: '/tmpimg/j27.png',
iconSrc: '/tmpimg/projectx_avatar256.png',
bookingAvailable: true,
maxPassengers: 8,
requiredCerts: [],
defects: [
{
type: 'engine',
severity: 'moderate',
description: 'Fuel line leaks at engine fitting.',
detail: `The gasket in the end of the fuel hose is damaged, and does not properly seal.
This will cause fuel to leak, and will allow air into the fuel chamber, causing a lean mixture,
and rough engine performance.`,
},
{
type: 'rigging',
severity: 'moderate',
description: 'Tiller extension is broken.',
detail:
'The tiller extension swivel is broken, and will not attach to the tiller.',
},
],
},
{
$id: '2',
name: 'Take5',
displayName: 'T5',
class: 'J/27',
year: 1985,
imgSrc: '/tmpimg/j27.png',
iconsrc: '/tmpimg/take5_avatar32.png',
bookingAvailable: true,
maxPassengers: 8,
requiredCerts: [],
},
{
$id: '3',
name: 'WeeBeestie',
displayName: 'WB',
class: 'Capri 25',
year: 1989,
imgSrc: '/tmpimg/capri25.png',
bookingAvailable: true,
maxPassengers: 6,
requiredCerts: [],
},
{
$id: '4',
name: 'Just My Imagination',
displayName: 'JMI',
class: 'Sirius 28',
year: 1989,
imgSrc: '/tmpimg/JMI.jpg',
bookingAvailable: true,
maxPassengers: 8,
requiredCerts: [],
},
];
export const useBoatStore = defineStore('boat', { async function fetchBoats() {
state: () => ({ try {
boats: getSampleData(), const response = await databases.listDocuments(
}), AppwriteIds.databaseId,
AppwriteIds.collection.boat
);
boatData.value = response.documents as Boat[];
} catch (error) {
console.error('Failed to fetch boats', error);
}
}
getters: {}, const boats = computed(() => {
if (!boatData.value) {
fetchBoats();
}
return boatData;
});
actions: { return { boats, fetchBoats };
// update () {
// }
},
}); });

View File

@@ -0,0 +1,65 @@
export const getSampleData = () => [
{
$id: '1',
name: 'ProjectX',
displayName: 'PX',
class: 'J/27',
year: 1981,
imgSrc: '/tmpimg/j27.png',
iconSrc: '/tmpimg/projectx_avatar256.png',
bookingAvailable: true,
maxPassengers: 8,
requiredCerts: [],
defects: [
{
type: 'engine',
severity: 'moderate',
description: 'Fuel line leaks at engine fitting.',
detail: `The gasket in the end of the fuel hose is damaged, and does not properly seal.
This will cause fuel to leak, and will allow air into the fuel chamber, causing a lean mixture,
and rough engine performance.`,
},
{
type: 'rigging',
severity: 'moderate',
description: 'Tiller extension is broken.',
detail:
'The tiller extension swivel is broken, and will not attach to the tiller.',
},
],
},
{
$id: '2',
name: 'Take5',
displayName: 'T5',
class: 'J/27',
year: 1985,
imgSrc: '/tmpimg/j27.png',
iconsrc: '/tmpimg/take5_avatar32.png',
bookingAvailable: true,
maxPassengers: 8,
requiredCerts: [],
},
{
$id: '3',
name: 'WeeBeestie',
displayName: 'WB',
class: 'Capri 25',
year: 1989,
imgSrc: '/tmpimg/capri25.png',
bookingAvailable: true,
maxPassengers: 6,
requiredCerts: [],
},
{
$id: '4',
name: 'Just My Imagination',
displayName: 'JMI',
class: 'Sirius 28',
year: 1989,
imgSrc: '/tmpimg/JMI.jpg',
bookingAvailable: true,
maxPassengers: 8,
requiredCerts: [],
},
];

View File

@@ -48,7 +48,7 @@ export function getSampleTimeBlocks(): Timeblock[] {
.map((b): Timeblock[] => { .map((b): Timeblock[] => {
return template.blocks.map((t): Timeblock => { return template.blocks.map((t): Timeblock => {
return { return {
id: 'id' + Math.random().toString(32).slice(2), $id: 'id' + Math.random().toString(32).slice(2),
boatId: b.$id, boatId: b.$id,
start: addToDate(tsToday, { day: i }).date + ' ' + t[0], start: addToDate(tsToday, { day: i }).date + ' ' + t[0],
end: addToDate(tsToday, { day: i }).date + ' ' + t[1], end: addToDate(tsToday, { day: i }).date + ' ' + t[1],

View File

@@ -9,17 +9,18 @@ import {
} from '@quasar/quasar-ui-qcalendar'; } from '@quasar/quasar-ui-qcalendar';
import { Reservation, Timeblock } from './schedule.types'; import { Reservation, Timeblock } from './schedule.types';
import { import { AppwriteIds, databases } from 'src/boot/appwrite';
getSampleReservations,
getSampleTimeBlocks,
} from './sampledata/schedule';
export const useScheduleStore = defineStore('schedule', () => { export const useScheduleStore = defineStore('schedule', () => {
// TODO: Implement functions to dynamically pull this data. // TODO: Implement functions to dynamically pull this data.
const reservations = ref<Reservation[]>(getSampleReservations()); const reservations = ref<Reservation[]>([]);
const timeblocks = ref<Timeblock[]>(getSampleTimeBlocks()); const timeblocks = ref<Timeblock[]>([]);
const getTimeblocksForDate = (date: string): Timeblock[] => { const getTimeblocksForDate = (date: string): Timeblock[] => {
// TODO: This needs to actually make sure we have the dates we need, stay in sync, etc.
if (!timeblocks.value) {
fetchTimeBlocks();
}
return timeblocks.value.filter((b) => return timeblocks.value.filter((b) =>
compareDate(parsed(b.start) as Timestamp, parsed(date) as Timestamp) compareDate(parsed(b.start) as Timestamp, parsed(date) as Timestamp)
); );
@@ -40,6 +41,17 @@ export const useScheduleStore = defineStore('schedule', () => {
}); });
}; };
async function fetchTimeBlocks() {
try {
const response = await databases.listDocuments(
AppwriteIds.databaseId,
AppwriteIds.collection.timeBlock
);
timeblocks.value = response.documents as Timeblock[];
} catch (error) {
console.error('Failed to fetch timeblocks', error);
}
}
// const getConflicts = (timeblock: Timeblock, boat: Boat) => { // const getConflicts = (timeblock: Timeblock, boat: Boat) => {
// const start = date.buildDate({ // const start = date.buildDate({
// hour: timeblock.start.hour, // hour: timeblock.start.hour,
@@ -55,6 +67,7 @@ export const useScheduleStore = defineStore('schedule', () => {
// }); // });
// return scheduleStore.getConflictingReservations(boat, start, end); // return scheduleStore.getConflictingReservations(boat, start, end);
// }; // };
const getConflictingReservations = ( const getConflictingReservations = (
resource: Boat, resource: Boat,
start: Date, start: Date,

View File

@@ -1,3 +1,4 @@
import { Models } from 'appwrite';
import type { Boat } from './boat'; import type { Boat } from './boat';
export type StatusTypes = 'tentative' | 'confirmed' | 'pending' | undefined; export type StatusTypes = 'tentative' | 'confirmed' | 'pending' | undefined;
@@ -17,8 +18,7 @@ export interface Reservation {
objects in here? */ objects in here? */
export type timeTuple = [start: string, end: string]; export type timeTuple = [start: string, end: string];
export interface Timeblock { export interface Timeblock extends Models.Document {
id: string;
boatId: string; boatId: string;
start: string; start: string;
end: string; end: string;

View File

@@ -92,6 +92,7 @@ export const useTaskStore = defineStore('tasks', {
docId docId
); );
this.tasks = this.tasks.filter((task) => docId !== task.$id); this.tasks = this.tasks.filter((task) => docId !== task.$id);
console.log(response);
} catch (error) { } catch (error) {
// Need some better error handling, here. // Need some better error handling, here.
console.error('Failed to delete task:', error); console.error('Failed to delete task:', error);