refactor: everything to nuxt.js
This commit is contained in:
41
app/utils/appwrite.ts
Normal file
41
app/utils/appwrite.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Client, Account, Databases, Functions, ID, Teams } from 'appwrite';
|
||||
|
||||
const client = new Client();
|
||||
|
||||
function initAppwriteClient(endpoint: string, projectId: string) {
|
||||
client.setEndpoint(endpoint).setProject(projectId);
|
||||
}
|
||||
|
||||
type AppwriteIDConfig = {
|
||||
databaseId: string;
|
||||
collection: {
|
||||
boat: string;
|
||||
reservation: string;
|
||||
interval: string;
|
||||
intervalTemplate: string;
|
||||
// task, taskTags, skillTags — parked; collections not yet created in bab_prod
|
||||
};
|
||||
function: {
|
||||
userinfo: string;
|
||||
};
|
||||
};
|
||||
|
||||
const AppwriteIds: AppwriteIDConfig = {
|
||||
databaseId: 'bab_prod',
|
||||
collection: {
|
||||
boat: 'boat',
|
||||
reservation: 'reservation',
|
||||
interval: 'interval',
|
||||
intervalTemplate: 'intervalTemplate',
|
||||
},
|
||||
function: {
|
||||
userinfo: 'userinfo',
|
||||
},
|
||||
};
|
||||
|
||||
const account = new Account(client);
|
||||
const databases = new Databases(client);
|
||||
const functions = new Functions(client);
|
||||
const teams = new Teams(client);
|
||||
|
||||
export { client, account, databases, functions, teams, ID, AppwriteIds, initAppwriteClient };
|
||||
20
app/utils/boat.types.ts
Normal file
20
app/utils/boat.types.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import type { Models } from 'appwrite';
|
||||
|
||||
export interface Boat extends Models.Document {
|
||||
$id: string;
|
||||
name: string;
|
||||
displayName?: string;
|
||||
class?: string;
|
||||
year?: number;
|
||||
imgSrc?: string;
|
||||
iconSrc?: string;
|
||||
bookingAvailable: boolean;
|
||||
requiredCerts: string[];
|
||||
maxPassengers: number;
|
||||
defects: {
|
||||
type: string;
|
||||
severity: string;
|
||||
description: string;
|
||||
detail?: string;
|
||||
}[];
|
||||
}
|
||||
7
app/utils/misc.ts
Normal file
7
app/utils/misc.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export function getNewId(): string {
|
||||
return [...Array(20)]
|
||||
.map(() => Math.floor(Math.random() * 16).toString(16))
|
||||
.join('');
|
||||
}
|
||||
|
||||
export type LoadingTypes = 'loaded' | 'pending' | 'error' | undefined;
|
||||
112
app/utils/navlinks.ts
Normal file
112
app/utils/navlinks.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { useAuthStore } from '~/stores/auth';
|
||||
|
||||
export type Link = {
|
||||
name: string;
|
||||
to?: string;
|
||||
icon: string;
|
||||
front_links?: boolean;
|
||||
enabled?: boolean;
|
||||
color?: string;
|
||||
sublinks?: Link[];
|
||||
requiredRoles?: string[];
|
||||
};
|
||||
|
||||
export const links: Link[] = [
|
||||
{
|
||||
name: 'Home',
|
||||
to: '/',
|
||||
icon: 'home',
|
||||
front_links: false,
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
name: 'Profile',
|
||||
to: '/profile',
|
||||
icon: 'account_circle',
|
||||
front_links: false,
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
name: 'Boats',
|
||||
to: '/boat',
|
||||
icon: 'sailing',
|
||||
front_links: true,
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
name: 'Schedule',
|
||||
to: '/schedule',
|
||||
icon: 'calendar_month',
|
||||
front_links: true,
|
||||
enabled: true,
|
||||
sublinks: [
|
||||
{ name: 'My View', to: '/schedule/list', icon: 'list', front_links: false, enabled: true },
|
||||
{ name: 'Book', to: '/schedule/book', icon: 'more_time', front_links: false, enabled: true },
|
||||
{ name: 'Calendar', to: '/schedule/view', icon: 'calendar_month', front_links: false, enabled: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Certifications',
|
||||
to: '/certification',
|
||||
icon: 'verified',
|
||||
front_links: true,
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
name: 'Checklists',
|
||||
to: '/checklist',
|
||||
icon: 'checklist',
|
||||
front_links: true,
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
name: 'Reference',
|
||||
to: '/reference',
|
||||
icon: 'info_outline',
|
||||
front_links: true,
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
name: 'Manage',
|
||||
icon: 'tune',
|
||||
enabled: true,
|
||||
requiredRoles: ['Schedule Admins'],
|
||||
color: 'negative',
|
||||
sublinks: [
|
||||
{
|
||||
name: 'Schedule',
|
||||
to: '/schedule/manage',
|
||||
icon: 'edit_calendar',
|
||||
front_links: false,
|
||||
enabled: true,
|
||||
color: 'accent',
|
||||
requiredRoles: ['Schedule Admins'],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export function useNavLinks() {
|
||||
const authStore = useAuthStore();
|
||||
|
||||
function hasRole(roles: string[] | undefined) {
|
||||
if (roles === undefined) return true;
|
||||
return authStore.hasRequiredRole(roles);
|
||||
}
|
||||
|
||||
const enabledLinks = links
|
||||
.filter((link) => link.enabled)
|
||||
.map((link) => {
|
||||
if (link.sublinks) {
|
||||
return {
|
||||
...link,
|
||||
sublinks: link.sublinks.filter(
|
||||
(sublink) => sublink.enabled && hasRole(sublink.requiredRoles)
|
||||
),
|
||||
};
|
||||
}
|
||||
return link;
|
||||
});
|
||||
|
||||
return { enabledLinks };
|
||||
}
|
||||
75
app/utils/schedule.ts
Normal file
75
app/utils/schedule.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { date } from 'quasar';
|
||||
import type { Boat } from '~/utils/boat.types';
|
||||
import type { Interval, IntervalTemplate, TimeTuple } from '~/utils/schedule.types';
|
||||
|
||||
export function arrayToTimeTuples(arr: string[]) {
|
||||
const timeTuples: TimeTuple[] = [];
|
||||
for (let i = 0; i < arr.length; i += 2) {
|
||||
timeTuples.push([arr[i]!, arr[i + 1]!]);
|
||||
}
|
||||
return timeTuples;
|
||||
}
|
||||
|
||||
export function timeTuplesOverlapped(tuples: TimeTuple[]): Interval[] {
|
||||
return intervalsOverlapped(
|
||||
tuples.map((tuples) => {
|
||||
return {
|
||||
resource: '',
|
||||
start: '01/01/2001 ' + tuples[0],
|
||||
end: '01/01/2001 ' + tuples[1],
|
||||
};
|
||||
})
|
||||
).map((t) => {
|
||||
return { ...t, start: t.start.split(' ')[1]!, end: t.end.split(' ')[1]! };
|
||||
});
|
||||
}
|
||||
|
||||
export function intervalsOverlapped(blocks: Interval[]): Interval[] {
|
||||
return Array.from(
|
||||
new Set(
|
||||
blocks
|
||||
.sort((a, b) => Date.parse(a.start) - Date.parse(b.start))
|
||||
.reduce((acc: Interval[], block, i, arr) => {
|
||||
if (i > 0 && block.start < arr[i - 1]!.end)
|
||||
acc.push(arr[i - 1]!, block);
|
||||
return acc;
|
||||
}, [])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function copyTimeTuples(tuples: TimeTuple[]): TimeTuple[] {
|
||||
return tuples.map((t) => Object.assign([], t));
|
||||
}
|
||||
|
||||
export function copyIntervalTemplate(template: IntervalTemplate): IntervalTemplate {
|
||||
return {
|
||||
...template,
|
||||
timeTuples: copyTimeTuples(template.timeTuples || []),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildInterval(resource: Boat, time: TimeTuple, blockDate: string): Interval {
|
||||
return {
|
||||
resource: resource.$id,
|
||||
start: new Date(blockDate + 'T' + time[0]).toISOString(),
|
||||
end: new Date(blockDate + 'T' + time[1]).toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
export const isPast = (itemDate: Date | string): boolean => {
|
||||
if (!(itemDate instanceof Date)) {
|
||||
itemDate = new Date(itemDate);
|
||||
}
|
||||
return itemDate < new Date();
|
||||
};
|
||||
|
||||
export function formatDate(inputDate: string | undefined): string {
|
||||
if (!inputDate) return '';
|
||||
return date.formatDate(new Date(inputDate), 'ddd MMM Do hh:mm A');
|
||||
}
|
||||
|
||||
export function formatTime(inputDate: string | undefined): string {
|
||||
if (!inputDate) return '';
|
||||
return date.formatDate(new Date(inputDate), 'hh:mm A');
|
||||
}
|
||||
28
app/utils/schedule.types.ts
Normal file
28
app/utils/schedule.types.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import type { Models } from 'appwrite';
|
||||
|
||||
export type StatusTypes = 'tentative' | 'confirmed' | 'pending' | undefined;
|
||||
export type Reservation = Interval & {
|
||||
user: string;
|
||||
status?: StatusTypes;
|
||||
reason: string;
|
||||
comment: string;
|
||||
members?: string[];
|
||||
guests?: string[];
|
||||
};
|
||||
|
||||
// 24 hrs in advance only 2 weekday, and 1 weekend slot
|
||||
// Within 24 hrs, any available slot
|
||||
|
||||
export type TimeTuple = [start: string, end: string];
|
||||
|
||||
export type Interval = Partial<Models.Document> & {
|
||||
resource: string;
|
||||
start: string;
|
||||
end: string;
|
||||
user?: string;
|
||||
};
|
||||
|
||||
export type IntervalTemplate = Partial<Models.Document> & {
|
||||
name: string;
|
||||
timeTuples: TimeTuple[];
|
||||
};
|
||||
1
app/utils/version.ts
Normal file
1
app/utils/version.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const APP_VERSION = '0.0.0';
|
||||
Reference in New Issue
Block a user