remove vue components
This commit is contained in:
0
resources/js/bootstrap.js
vendored
0
resources/js/bootstrap.js
vendored
@@ -1,12 +0,0 @@
|
|||||||
import Router from "@/router";
|
|
||||||
import { createPinia } from "pinia";
|
|
||||||
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
|
|
||||||
import { createApp } from "vue";
|
|
||||||
import App from "./views/App.vue";
|
|
||||||
import "uno.css";
|
|
||||||
import "../css/app.scss";
|
|
||||||
|
|
||||||
const pinia = createPinia();
|
|
||||||
pinia.use(piniaPluginPersistedstate);
|
|
||||||
|
|
||||||
createApp(App).use(pinia).use(Router).mount("#app");
|
|
||||||
@@ -1,619 +0,0 @@
|
|||||||
import { useUserStore } from "@/store/UserStore";
|
|
||||||
import { createRouter, createWebHistory } from "vue-router";
|
|
||||||
import { api } from "../helpers/api";
|
|
||||||
import { useApplicationStore } from "../store/ApplicationStore";
|
|
||||||
import { updateSEOTags } from "../helpers/seo";
|
|
||||||
|
|
||||||
export const routes = [
|
|
||||||
{
|
|
||||||
path: "/",
|
|
||||||
name: "home",
|
|
||||||
meta: {
|
|
||||||
title: "Home",
|
|
||||||
description:
|
|
||||||
"STEMMechanics, a family-run company based in Cairns, Queensland, creates fantastic STEM-focused programs and activities that are both entertaining and educational.",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/Home.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/blog",
|
|
||||||
name: "blog",
|
|
||||||
meta: {
|
|
||||||
title: "Blog",
|
|
||||||
},
|
|
||||||
component: () => import(/* webpackPrefetch: true */ "@/views/Blog.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/article",
|
|
||||||
redirect: "/blog",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: ":slug",
|
|
||||||
name: "article",
|
|
||||||
component: () => import("@/views/Article.vue"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/workshops",
|
|
||||||
name: "workshops",
|
|
||||||
meta: {
|
|
||||||
title: "Workshops",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import(/* webpackPreload: true */ "@/views/Workshops.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/event",
|
|
||||||
redirect: "/workshops",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: ":id",
|
|
||||||
name: "event",
|
|
||||||
component: () => import("@/views/Event.vue"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/verify-email",
|
|
||||||
name: "verify-email",
|
|
||||||
meta: {
|
|
||||||
title: "Verify Email",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/EmailVerify.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/resend-verify-email",
|
|
||||||
name: "resend-verify-email",
|
|
||||||
meta: {
|
|
||||||
title: "Resend Verification Email",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/ResendEmailVerify.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/reset-password",
|
|
||||||
name: "reset-password",
|
|
||||||
meta: {
|
|
||||||
title: "Reset Password",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/ResetPassword.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/privacy",
|
|
||||||
name: "privacy",
|
|
||||||
meta: {
|
|
||||||
title: "Privacy Policy",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/Privacy.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/rules",
|
|
||||||
name: "rules",
|
|
||||||
meta: {
|
|
||||||
title: "Rules",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/Rules.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/community",
|
|
||||||
name: "community",
|
|
||||||
meta: {
|
|
||||||
title: "Community",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/Community.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/minecraft",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "",
|
|
||||||
name: "minecraft",
|
|
||||||
meta: {
|
|
||||||
title: "Minecraft",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/Minecraft.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "curve",
|
|
||||||
name: "minecraft-curve",
|
|
||||||
meta: {
|
|
||||||
title: "Minecraft Curve",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/MinecraftCurve.vue"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/login",
|
|
||||||
name: "login",
|
|
||||||
meta: {
|
|
||||||
title: "Login",
|
|
||||||
middleware: "guest",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import(/* webpackPrefetch: true */ "@/views/Login.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/logout",
|
|
||||||
name: "logout",
|
|
||||||
meta: {
|
|
||||||
title: "Logout",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/Logout.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/contact",
|
|
||||||
name: "contact",
|
|
||||||
meta: {
|
|
||||||
title: "Contact",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import(/* webpackPrefetch: true */ "@/views/Contact.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/conduct",
|
|
||||||
redirect: { name: "code-of-conduct" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/code-of-conduct",
|
|
||||||
name: "code-of-conduct",
|
|
||||||
meta: {
|
|
||||||
title: "Code of Conduct",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/CodeOfConduct.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/terms",
|
|
||||||
redirect: { name: "terms-and-conditions" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/terms-and-conditions",
|
|
||||||
name: "terms-and-conditions",
|
|
||||||
meta: {
|
|
||||||
title: "Terms and Conditions",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/TermsAndConditions.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/register",
|
|
||||||
name: "register",
|
|
||||||
meta: {
|
|
||||||
title: "Register",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import(/* webpackPrefetch: true */ "@/views/Register.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/dashboard",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "",
|
|
||||||
name: "dashboard",
|
|
||||||
meta: {
|
|
||||||
title: "Dashboard",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import(
|
|
||||||
/* webpackPrefetch: true */ "@/views/dashboard/Dashboard.vue"
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "analytics",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "",
|
|
||||||
name: "dashboard-analytics-list",
|
|
||||||
meta: {
|
|
||||||
title: "Analytics",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/AnalyticsList.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ":id",
|
|
||||||
name: "dashboard-analytics-item",
|
|
||||||
meta: {
|
|
||||||
title: "Analytics Session",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/AnalyticsItem.vue"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "articles",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "",
|
|
||||||
name: "dashboard-article-list",
|
|
||||||
meta: {
|
|
||||||
title: "Articles",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/ArticleList.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "create",
|
|
||||||
name: "dashboard-article-create",
|
|
||||||
meta: {
|
|
||||||
title: "Create Article",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/ArticleEdit.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ":id",
|
|
||||||
name: "dashboard-article-edit",
|
|
||||||
meta: {
|
|
||||||
title: "Edit Article",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/ArticleEdit.vue"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "events",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "",
|
|
||||||
name: "dashboard-event-list",
|
|
||||||
meta: {
|
|
||||||
title: "Events",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/EventList.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "create",
|
|
||||||
name: "dashboard-event-create",
|
|
||||||
meta: {
|
|
||||||
title: "Create Event",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/EventEdit.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ":id",
|
|
||||||
name: "dashboard-event-edit",
|
|
||||||
meta: {
|
|
||||||
title: "Event",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/EventEdit.vue"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "details",
|
|
||||||
name: "dashboard-account-details",
|
|
||||||
meta: {
|
|
||||||
title: "Account Details",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/dashboard/UserEdit.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "users",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "",
|
|
||||||
name: "dashboard-user-list",
|
|
||||||
meta: {
|
|
||||||
title: "Users",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/UserList.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "create",
|
|
||||||
name: "dashboard-user-create",
|
|
||||||
meta: {
|
|
||||||
title: "Create User",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/UserEdit.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ":id",
|
|
||||||
name: "dashboard-user-edit",
|
|
||||||
meta: {
|
|
||||||
title: "Edit User",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/UserEdit.vue"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "media",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "",
|
|
||||||
name: "dashboard-media-list",
|
|
||||||
meta: {
|
|
||||||
title: "Media",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/MediaList.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "create",
|
|
||||||
name: "dashboard-media-create",
|
|
||||||
meta: {
|
|
||||||
title: "Upload Media",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/MediaEdit.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ":id",
|
|
||||||
name: "dashboard-media-edit",
|
|
||||||
meta: {
|
|
||||||
title: "Edit Media",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/MediaEdit.vue"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "shortlinks",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "",
|
|
||||||
name: "dashboard-shortlink-list",
|
|
||||||
meta: {
|
|
||||||
title: "Shortlink",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/ShortlinkList.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "create",
|
|
||||||
name: "dashboard-shortlink-create",
|
|
||||||
meta: {
|
|
||||||
title: "Create Shortlink",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/ShortlinkEdit.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ":id",
|
|
||||||
name: "dashboard-shortlink-edit",
|
|
||||||
meta: {
|
|
||||||
title: "Edit Shortlink",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import("@/views/dashboard/ShortlinkEdit.vue"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "discord-bot-logs",
|
|
||||||
name: "dashboard-discord-bot-logs",
|
|
||||||
meta: {
|
|
||||||
title: "Discord Bot Logs",
|
|
||||||
middleware: "authenticated",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/dashboard/DiscordBotLogs.vue"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/forgot-password",
|
|
||||||
name: "forgot-password",
|
|
||||||
meta: {
|
|
||||||
title: "Forgot Password",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/ForgotPassword.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/file/:id",
|
|
||||||
name: "file",
|
|
||||||
meta: {
|
|
||||||
title: "File",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/File.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/cart",
|
|
||||||
name: "cart",
|
|
||||||
meta: {
|
|
||||||
title: "Cart",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/Cart.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/:catchAll(.*)",
|
|
||||||
name: "not-found",
|
|
||||||
meta: {
|
|
||||||
title: "Page not found",
|
|
||||||
hideInEditor: true,
|
|
||||||
},
|
|
||||||
component: () => import("@/views/404.vue"),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const router = createRouter({
|
|
||||||
history: createWebHistory(),
|
|
||||||
routes,
|
|
||||||
scrollBehavior() {
|
|
||||||
return { top: 0 };
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// export let activeRoutes = [];
|
|
||||||
|
|
||||||
router.beforeEach(async (to, from, next) => {
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const applicationStore = useApplicationStore();
|
|
||||||
|
|
||||||
applicationStore.hydrated = false;
|
|
||||||
applicationStore.clearDynamicTitle();
|
|
||||||
|
|
||||||
if (applicationStore.pageLoaderTimeout !== 0) {
|
|
||||||
window.clearTimeout(applicationStore.pageLoaderTimeout);
|
|
||||||
applicationStore.pageLoaderTimeout = window.setTimeout(() => {
|
|
||||||
const pageLoadingElem = document.getElementById("sm-page-loading");
|
|
||||||
if (pageLoadingElem !== null) {
|
|
||||||
pageLoadingElem.style.display = "flex";
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (to.meta.middleware == "authenticated") {
|
|
||||||
if (userStore.id) {
|
|
||||||
api.get({
|
|
||||||
url: "/me",
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
userStore.setUserDetails(res.data.user);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
if (err.status == 401) {
|
|
||||||
userStore.clearUser();
|
|
||||||
|
|
||||||
window.location.href = `/login?redirect=${to.fullPath}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!userStore.id) {
|
|
||||||
next({
|
|
||||||
name: "login",
|
|
||||||
query: { redirect: encodeURIComponent(to.fullPath) },
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
api.post({
|
|
||||||
url: "/analytics",
|
|
||||||
body: {
|
|
||||||
type: "pageview",
|
|
||||||
path: to.fullPath,
|
|
||||||
},
|
|
||||||
}).catch(() => {
|
|
||||||
/* empty */
|
|
||||||
});
|
|
||||||
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.afterEach((to, from) => {
|
|
||||||
const applicationStore = useApplicationStore();
|
|
||||||
|
|
||||||
if (from.name !== undefined) {
|
|
||||||
document.body.classList.remove(`page-${from.name}`);
|
|
||||||
}
|
|
||||||
document.body.classList.add(`page-${to.name}`);
|
|
||||||
|
|
||||||
window.setTimeout(() => {
|
|
||||||
const getMetaValue = (tag, defaultValue = "") => {
|
|
||||||
const getMeta = (obj, tag) => {
|
|
||||||
const tagHierarchy = tag.split(".");
|
|
||||||
|
|
||||||
const nearestWithMeta = obj.matched
|
|
||||||
.slice()
|
|
||||||
.reverse()
|
|
||||||
.reduce(
|
|
||||||
(acc, r) => acc || (r.meta && r.meta[tagHierarchy[0]]),
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
if (nearestWithMeta) {
|
|
||||||
let result = nearestWithMeta;
|
|
||||||
for (let i = 1; i < tagHierarchy.length; i++) {
|
|
||||||
result = result[tagHierarchy[i]];
|
|
||||||
if (!result) break;
|
|
||||||
}
|
|
||||||
if (result !== undefined) return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const nearestMeta = getMeta(to, tag);
|
|
||||||
if (nearestMeta == null) {
|
|
||||||
const previousMeta = getMeta(from, tag);
|
|
||||||
if (previousMeta == null) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return previousMeta;
|
|
||||||
}
|
|
||||||
return nearestMeta;
|
|
||||||
};
|
|
||||||
|
|
||||||
updateSEOTags({
|
|
||||||
title: getMetaValue("title"),
|
|
||||||
description: getMetaValue("description"),
|
|
||||||
keywords: getMetaValue("keywords", []),
|
|
||||||
robots: {
|
|
||||||
index: getMetaValue(
|
|
||||||
"robots.index",
|
|
||||||
!to.meta.middleware
|
|
||||||
? true
|
|
||||||
: to.meta.middleware != "authenticated",
|
|
||||||
),
|
|
||||||
follow: getMetaValue(
|
|
||||||
"robots.follow",
|
|
||||||
!to.meta.middleware
|
|
||||||
? true
|
|
||||||
: to.meta.middleware != "authenticated",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
url: getMetaValue("url", to.path),
|
|
||||||
image: getMetaValue("image", ""),
|
|
||||||
});
|
|
||||||
}, 10);
|
|
||||||
|
|
||||||
window.setTimeout(() => {
|
|
||||||
const autofocusElement = document.querySelector("[autofocus]");
|
|
||||||
if (autofocusElement) {
|
|
||||||
autofocusElement.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
const hash = window.location.hash;
|
|
||||||
if (hash) {
|
|
||||||
const target = document.querySelector(hash);
|
|
||||||
if (target) {
|
|
||||||
target.scrollIntoView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 10);
|
|
||||||
|
|
||||||
if (applicationStore.pageLoaderTimeout !== 0) {
|
|
||||||
window.clearTimeout(applicationStore.pageLoaderTimeout);
|
|
||||||
applicationStore.pageLoaderTimeout = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pageLoadingElem = document.getElementById("sm-page-loading");
|
|
||||||
if (pageLoadingElem !== null) {
|
|
||||||
pageLoadingElem.style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
applicationStore.hydrated = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
export default router;
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
import { defineStore } from "pinia";
|
|
||||||
|
|
||||||
type ApplicationStoreEventKeyUpCallback = (event: KeyboardEvent) => boolean;
|
|
||||||
type ApplicationStoreEventKeyPressCallback = (event: KeyboardEvent) => boolean;
|
|
||||||
|
|
||||||
export interface ApplicationStore {
|
|
||||||
hydrated: boolean;
|
|
||||||
unavailable: boolean;
|
|
||||||
dynamicTitle: string;
|
|
||||||
eventKeyUpStack: ApplicationStoreEventKeyUpCallback[];
|
|
||||||
eventKeyPressStack: ApplicationStoreEventKeyPressCallback[];
|
|
||||||
pageLoaderTimeout: number;
|
|
||||||
_addedListener: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useApplicationStore = defineStore({
|
|
||||||
id: "application",
|
|
||||||
state: (): ApplicationStore => ({
|
|
||||||
hydrated: false,
|
|
||||||
unavailable: false,
|
|
||||||
dynamicTitle: "",
|
|
||||||
eventKeyUpStack: [],
|
|
||||||
eventKeyPressStack: [],
|
|
||||||
pageLoaderTimeout: 0,
|
|
||||||
_addedListener: false,
|
|
||||||
}),
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
async setDynamicTitle(title: string) {
|
|
||||||
this.$state.dynamicTitle = title;
|
|
||||||
document.title = `STEMMechanics | ${title}`;
|
|
||||||
},
|
|
||||||
|
|
||||||
clearDynamicTitle() {
|
|
||||||
this.$state.dynamicTitle = "";
|
|
||||||
},
|
|
||||||
|
|
||||||
addKeyUpListener(callback: ApplicationStoreEventKeyUpCallback) {
|
|
||||||
this.eventKeyUpStack.push(callback);
|
|
||||||
|
|
||||||
if (!this._addedListener) {
|
|
||||||
document.addEventListener("keyup", (event: KeyboardEvent) => {
|
|
||||||
this.eventKeyUpStack.every(
|
|
||||||
(item: ApplicationStoreEventKeyUpCallback) => {
|
|
||||||
const result = item(event);
|
|
||||||
if (result) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
removeKeyUpListener(callback: ApplicationStoreEventKeyUpCallback) {
|
|
||||||
this.eventKeyUpStack = this.eventKeyUpStack.filter(
|
|
||||||
(item: ApplicationStoreEventKeyUpCallback) => item !== callback,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
addKeyPressListener(callback: ApplicationStoreEventKeyPressCallback) {
|
|
||||||
this.eventKeyPressStack.push(callback);
|
|
||||||
|
|
||||||
if (!this._addedListener) {
|
|
||||||
document.addEventListener(
|
|
||||||
"keypress",
|
|
||||||
(event: KeyboardEvent) => {
|
|
||||||
this.eventKeyPressStack.every(
|
|
||||||
(item: ApplicationStoreEventKeyPressCallback) => {
|
|
||||||
const result = item(event);
|
|
||||||
if (result) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
removeKeyPressListener(
|
|
||||||
callback: ApplicationStoreEventKeyPressCallback,
|
|
||||||
) {
|
|
||||||
this.eventKeyPressStack = this.eventKeyPressStack.filter(
|
|
||||||
(item: ApplicationStoreEventKeyPressCallback) =>
|
|
||||||
item !== callback,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import { DefineStoreOptions, defineStore } from "pinia";
|
|
||||||
|
|
||||||
interface CacheItem {
|
|
||||||
url: string;
|
|
||||||
data: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useCacheStore = defineStore({
|
|
||||||
id: "cache",
|
|
||||||
state: () => ({
|
|
||||||
cache: [] as CacheItem[],
|
|
||||||
}),
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
// Method to retrieve cached JSON data based on a URL
|
|
||||||
getCacheByUrl(url: string) {
|
|
||||||
const cachedItem = this.cache.find((item) => item.url === url);
|
|
||||||
return cachedItem ? cachedItem.data : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Method to update the cache with new data and check for modifications
|
|
||||||
updateCache(url: string, newData: unknown): boolean {
|
|
||||||
const index = this.cache.findIndex((item) => item.url === url);
|
|
||||||
|
|
||||||
if (index !== -1) {
|
|
||||||
// If the URL is already in the cache, check for modifications
|
|
||||||
const existingData = this.cache[index].data;
|
|
||||||
|
|
||||||
if (JSON.stringify(existingData) === JSON.stringify(newData)) {
|
|
||||||
// Data is not modified, return false
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// Data is modified, update the cache
|
|
||||||
this.cache[index].data = newData;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If the URL is not in the cache, add it
|
|
||||||
this.cache.push({ url, data: newData });
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Method to clear the cache for a specific URL
|
|
||||||
clearCacheByUrl(url: string) {
|
|
||||||
const index = this.cache.findIndex((item) => item.url === url);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.cache.splice(index, 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Method to clear the entire cache
|
|
||||||
clearCache() {
|
|
||||||
this.cache = [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
persist: true,
|
|
||||||
} as DefineStoreOptions<string, unknown, unknown, unknown> & {
|
|
||||||
persist?: boolean;
|
|
||||||
});
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
import { defineStore } from "pinia";
|
|
||||||
|
|
||||||
export interface ToastOptions {
|
|
||||||
id?: number;
|
|
||||||
title?: string;
|
|
||||||
content: string;
|
|
||||||
type?: string;
|
|
||||||
loader?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ToastItem {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
content: string;
|
|
||||||
type: string;
|
|
||||||
loader: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ToastStore {
|
|
||||||
toasts: ToastItem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const defaultToastItem: ToastItem = {
|
|
||||||
id: 0,
|
|
||||||
title: "",
|
|
||||||
content: "",
|
|
||||||
type: "primary",
|
|
||||||
loader: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useToastStore = defineStore({
|
|
||||||
id: "toasts",
|
|
||||||
state: (): ToastStore => ({
|
|
||||||
toasts: [],
|
|
||||||
}),
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
addToast(toast: ToastOptions): number {
|
|
||||||
while (
|
|
||||||
!toast.id ||
|
|
||||||
toast.id == 0 ||
|
|
||||||
this.toasts.find((item: ToastItem) => item.id === toast.id)
|
|
||||||
) {
|
|
||||||
toast.id =
|
|
||||||
Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
toast.title = toast.title || defaultToastItem.title;
|
|
||||||
toast.type = toast.type || defaultToastItem.type;
|
|
||||||
|
|
||||||
this.toasts.push(toast);
|
|
||||||
return toast.id;
|
|
||||||
},
|
|
||||||
|
|
||||||
clearToast(id: number): void {
|
|
||||||
this.toasts = this.toasts.filter(
|
|
||||||
(item: ToastItem) => item.id !== id
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
updateToast(id: number, updatedFields: Partial<ToastOptions>): void {
|
|
||||||
const toastToUpdate = this.toasts.find(
|
|
||||||
(item: ToastItem) => item.id === id
|
|
||||||
);
|
|
||||||
|
|
||||||
if (toastToUpdate) {
|
|
||||||
toastToUpdate.title =
|
|
||||||
updatedFields.title || toastToUpdate.title;
|
|
||||||
toastToUpdate.content =
|
|
||||||
updatedFields.content || toastToUpdate.content;
|
|
||||||
toastToUpdate.type = updatedFields.type || toastToUpdate.type;
|
|
||||||
if (
|
|
||||||
Object.prototype.hasOwnProperty.call(
|
|
||||||
updatedFields,
|
|
||||||
"loader"
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
toastToUpdate.loader = updatedFields.loader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
import { defineStore, DefineStoreOptions } from "pinia";
|
|
||||||
|
|
||||||
export interface UserDetails {
|
|
||||||
id: string;
|
|
||||||
username: string;
|
|
||||||
first_name: string;
|
|
||||||
last_name: string;
|
|
||||||
display_name: string;
|
|
||||||
email: string;
|
|
||||||
phone: string;
|
|
||||||
permissions: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserState {
|
|
||||||
id: string;
|
|
||||||
token: string;
|
|
||||||
username: string;
|
|
||||||
firstName: string;
|
|
||||||
lastName: string;
|
|
||||||
displayName: string;
|
|
||||||
email: string;
|
|
||||||
phone: string;
|
|
||||||
permissions: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useUserStore = defineStore({
|
|
||||||
id: "user",
|
|
||||||
state: (): UserState => {
|
|
||||||
return {
|
|
||||||
id: "",
|
|
||||||
token: "",
|
|
||||||
username: "",
|
|
||||||
firstName: "",
|
|
||||||
lastName: "",
|
|
||||||
displayName: "",
|
|
||||||
email: "",
|
|
||||||
phone: "",
|
|
||||||
permissions: [],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
async setUserDetails(user: UserDetails) {
|
|
||||||
this.$state.id = user.id;
|
|
||||||
this.$state.username = user.username;
|
|
||||||
this.$state.firstName = user.first_name;
|
|
||||||
this.$state.lastName = user.last_name;
|
|
||||||
this.$state.displayName = user.display_name;
|
|
||||||
this.$state.email = user.email;
|
|
||||||
this.$state.phone = user.phone;
|
|
||||||
this.$state.permissions = user.permissions || [];
|
|
||||||
},
|
|
||||||
|
|
||||||
async setUserToken(token: string) {
|
|
||||||
this.$state.token = token;
|
|
||||||
},
|
|
||||||
|
|
||||||
clearUser() {
|
|
||||||
this.$state.id = null;
|
|
||||||
this.$state.token = null;
|
|
||||||
this.$state.username = null;
|
|
||||||
this.$state.firstName = null;
|
|
||||||
this.$state.lastName = null;
|
|
||||||
this.$state.displayName = null;
|
|
||||||
this.$state.email = null;
|
|
||||||
this.$state.phone = null;
|
|
||||||
this.$state.permissions = [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
persist: true,
|
|
||||||
} as DefineStoreOptions<string, unknown, unknown, unknown> & { persist?: boolean });
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import { expect, describe, it } from "vitest";
|
|
||||||
import { SMDate } from "../helpers/datetime";
|
|
||||||
|
|
||||||
describe("format()", () => {
|
|
||||||
it("should return an empty string when the first argument is not a Date object", () => {
|
|
||||||
const result = new SMDate("not a date").format("yyyy-MM-dd");
|
|
||||||
expect(result).toEqual("");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should format the date correctly", () => {
|
|
||||||
const date = new Date("2022-02-19T12:34:56");
|
|
||||||
const result = new SMDate(date).format("yyyy-MM-dd HH:mm:ss");
|
|
||||||
expect(result).toEqual("2022-02-19 12:34:56");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should handle single-digit month and day", () => {
|
|
||||||
const date = new Date("2022-01-01T00:00:00");
|
|
||||||
const result = new SMDate(date).format("yy-M-d");
|
|
||||||
expect(result).toEqual("22-1-1");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should handle day of week and month name abbreviations", () => {
|
|
||||||
const date = new Date("2022-03-22T00:00:00");
|
|
||||||
const result = new SMDate(date).format("EEE, MMM dd, yyyy");
|
|
||||||
expect(result).toEqual("Tue, Mar 22, 2022");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should handle 12-hour clock with am/pm", () => {
|
|
||||||
const date = new Date("2022-01-01T12:34:56");
|
|
||||||
const result = new SMDate(date).format("hh:mm:ss aa");
|
|
||||||
expect(result).toEqual("12:34:56 pm");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { expect, describe, it } from "vitest";
|
|
||||||
import { toTitleCase } from "../helpers/string";
|
|
||||||
|
|
||||||
describe("toTitleCase()", () => {
|
|
||||||
it("should return a converted title case string", () => {
|
|
||||||
const result = toTitleCase("titlecase");
|
|
||||||
expect(result).toEqual("Titlecase");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return a converted title case string and spaces", () => {
|
|
||||||
const result = toTitleCase("titlecase_and_more");
|
|
||||||
expect(result).toEqual("Titlecase And More");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import { expect, describe, it } from "vitest";
|
|
||||||
import { Email } from "../helpers/validate";
|
|
||||||
|
|
||||||
describe("Email()", () => {
|
|
||||||
it("should return valid=false when an invalid email address is passed to the validate function", async () => {
|
|
||||||
const v = Email();
|
|
||||||
const result = await v.validate("invalid email");
|
|
||||||
expect(result.valid).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return valid=false when an invalid email address is passed to the validate function", async () => {
|
|
||||||
const v = Email();
|
|
||||||
const result = await v.validate("fake@outlook");
|
|
||||||
expect(result.valid).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return valid=true when an valid email address is passed to the validate function", async () => {
|
|
||||||
const v = Email();
|
|
||||||
const result = await v.validate("fake@outlook.com");
|
|
||||||
expect(result.valid).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return valid=true when an valid email address is passed to the validate function", async () => {
|
|
||||||
const v = Email();
|
|
||||||
const result = await v.validate("fake@outlook.com.au");
|
|
||||||
expect(result.valid).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user