mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-10 15:58:38 +01:00
new selfhosted version
This commit is contained in:
33
dashboard/stores/DomainStore.ts
Normal file
33
dashboard/stores/DomainStore.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
import type { TDomainSimpleRes } from "~/server/api/domains/list";
|
||||
|
||||
export const useDomainStore = defineStore('domain', () => {
|
||||
|
||||
const domains = shallowRef<TDomainSimpleRes[]>([]);
|
||||
const activeDomain = shallowRef<TDomainSimpleRes>();
|
||||
const domainPending = ref<boolean>(false);
|
||||
|
||||
async function fetchDomains() {
|
||||
domains.value = [];
|
||||
activeDomain.value = undefined;
|
||||
domainPending.value = true;
|
||||
await nextTick();
|
||||
const res = await useAuthFetchSync<TDomainSimpleRes[]>('/api/domains/list');
|
||||
domains.value = res;
|
||||
if (domains.value.length > 0) activeDomain.value = domains.value[0];
|
||||
domainPending.value = false;
|
||||
}
|
||||
|
||||
function setActive(domain_id: string) {
|
||||
activeDomain.value = domains.value.find(e => domain_id === e._id.toString());
|
||||
}
|
||||
|
||||
return {
|
||||
domains,
|
||||
activeDomain,
|
||||
fetchDomains,
|
||||
setActive,
|
||||
domainPending
|
||||
}
|
||||
|
||||
})
|
||||
63
dashboard/stores/PremiumStore.ts
Normal file
63
dashboard/stores/PremiumStore.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
import type { TUserPlanInfo } from "~/server/api/user/plan";
|
||||
import { getPlanFromId, type PLAN_DATA } from '@data/PLANS';
|
||||
import { getPlanFromPrice } from '~/shared/data/PLANS';
|
||||
|
||||
export const usePremiumStore = defineStore('premium', () => {
|
||||
|
||||
const plan = shallowRef<TUserPlanInfo>();
|
||||
const planPending = ref<boolean>(false);
|
||||
|
||||
async function fetchPremium() {
|
||||
plan.value = undefined;
|
||||
planPending.value = true;
|
||||
await nextTick();
|
||||
const res = await useAuthFetchSync<TUserPlanInfo>('/api/user/plan');
|
||||
plan.value = res;
|
||||
planPending.value = false;
|
||||
}
|
||||
|
||||
const billingPeriodPercent = computed(() => {
|
||||
if (!plan.value) return 0;
|
||||
const start = plan.value.start_at;
|
||||
const end = plan.value.end_at;
|
||||
const duration = end - start;
|
||||
const remaining = end - Date.now();
|
||||
const percent = 100 - Math.floor(100 / duration * remaining);
|
||||
return percent;
|
||||
});
|
||||
|
||||
const planInfo = computed<PLAN_DATA | undefined>(() => {
|
||||
if (!plan.value) return;
|
||||
return getPlanFromId(plan.value.premium_type);
|
||||
});
|
||||
|
||||
const isAnnual = computed(() => {
|
||||
return planInfo.value?.TAG.endsWith('_ANNUAL');
|
||||
})
|
||||
|
||||
const isCanceled = computed(() => {
|
||||
return plan.value?.canceled;
|
||||
})
|
||||
|
||||
function getPlanUsingPrice(price: string) {
|
||||
const price_live = getPlanFromPrice(price, false);
|
||||
if (!price_live) {
|
||||
const price_test = getPlanFromPrice(price, true);
|
||||
return price_test;
|
||||
}
|
||||
return price_live;
|
||||
}
|
||||
|
||||
return {
|
||||
fetchPremium,
|
||||
plan,
|
||||
planPending,
|
||||
billingPeriodPercent,
|
||||
planInfo,
|
||||
isAnnual,
|
||||
isCanceled,
|
||||
getPlanUsingPrice
|
||||
}
|
||||
|
||||
})
|
||||
121
dashboard/stores/ProjectStore.ts
Normal file
121
dashboard/stores/ProjectStore.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import type { TPendingInvite } from "~/server/api/members/pending";
|
||||
import type { TProject } from "~/shared/schema/project/ProjectSchema";
|
||||
import type { TPermission } from "~/shared/schema/TeamMemberSchema";
|
||||
|
||||
export const useProjectStore = defineStore('project', () => {
|
||||
|
||||
const projects = shallowRef<(TProject & { guest?: boolean })[]>([]);
|
||||
const activeProject = shallowRef<(TProject & { guest?: boolean })>();
|
||||
const pid = computed(() => activeProject.value?._id.toString());
|
||||
const permissions = ref<TPermission>();
|
||||
const isOwner = computed(() => !activeProject.value?.guest);
|
||||
|
||||
const firstInteraction = ref<boolean>(false);
|
||||
|
||||
const pendingInvites = ref<TPendingInvite[]>([]);
|
||||
|
||||
const isActiveProjectGuest = computed(() => {
|
||||
const target = projects.value.find(e => e._id.toString() === pid.value);
|
||||
if (!target) return false;
|
||||
return target.guest === true;
|
||||
})
|
||||
|
||||
|
||||
function getLocalSavedProject() {
|
||||
return localStorage.getItem(`litlyx_preference_last_project_selected`);
|
||||
}
|
||||
|
||||
function setLocalSavedProject(save_pid: string) {
|
||||
localStorage.setItem(`litlyx_preference_last_project_selected`, save_pid);
|
||||
}
|
||||
|
||||
async function fetchPendingInvites() {
|
||||
try {
|
||||
const result = await useAuthFetchSync<TPendingInvite[]>('/api/members/pending');
|
||||
pendingInvites.value = result;
|
||||
} catch (ex) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchProjects() {
|
||||
|
||||
const [res, resGuest] = await Promise.all([
|
||||
useAuthFetchSync<TProject[]>('/api/project/list'),
|
||||
useAuthFetchSync<TProject[]>('/api/project/list_guest')
|
||||
]);
|
||||
|
||||
projects.value = [...res, ...resGuest.map(e => ({ ...e, guest: true }))];
|
||||
|
||||
if (res.length > 0) {
|
||||
const saved = getLocalSavedProject();
|
||||
if (saved) {
|
||||
const index = projects.value.findIndex(e => e._id.toString() === saved);
|
||||
if (index == -1) {
|
||||
activeProject.value = projects.value[0];
|
||||
await fetchFirstInteraction();
|
||||
return;
|
||||
}
|
||||
activeProject.value = projects.value[index];
|
||||
await fetchFirstInteraction();
|
||||
return;
|
||||
}
|
||||
activeProject.value = projects.value[0];
|
||||
await fetchFirstInteraction();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function fetchFirstInteraction() {
|
||||
try {
|
||||
firstInteraction.value = await useAuthFetchSync<boolean>('/api/project/first_interaction');
|
||||
console.log('First interaction:', firstInteraction.value)
|
||||
return firstInteraction.value;
|
||||
|
||||
} catch (ex) {
|
||||
console.log('Cannot get first interaction data');
|
||||
console.error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchActivePermissions() {
|
||||
permissions.value = await useAuthFetchSync<TPermission>('/api/members/me');
|
||||
return permissions.value;
|
||||
}
|
||||
|
||||
async function setActive(pid: string) {
|
||||
|
||||
console.log('SETTING ACTIVE PROJECT', pid);
|
||||
|
||||
activeProject.value = projects.value.find(e => pid === e._id.toString());
|
||||
setLocalSavedProject(pid);
|
||||
|
||||
const domainStore = useDomainStore();
|
||||
const snapshotStore = useSnapshotStore();
|
||||
|
||||
await fetchFirstInteraction(),
|
||||
|
||||
await Promise.all([
|
||||
domainStore.fetchDomains(),
|
||||
snapshotStore.fetchSnapshots(),
|
||||
fetchActivePermissions(),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
isActiveProjectGuest,
|
||||
projects,
|
||||
activeProject,
|
||||
pid,
|
||||
fetchActivePermissions,
|
||||
fetchProjects,
|
||||
setActive,
|
||||
permissions,
|
||||
isOwner,
|
||||
fetchPendingInvites,
|
||||
pendingInvites,
|
||||
firstInteraction,
|
||||
fetchFirstInteraction
|
||||
}
|
||||
})
|
||||
170
dashboard/stores/SnapshotStore.ts
Normal file
170
dashboard/stores/SnapshotStore.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
|
||||
import type { TProjectSnapshot } from "~/shared/schema/project/ProjectSnapshot";
|
||||
import * as fns from 'date-fns';
|
||||
|
||||
export type DefaultSnapshot = Omit<TProjectSnapshot, 'project_id'> & { default: true }
|
||||
export type GenericSnapshot = TProjectSnapshot | DefaultSnapshot;
|
||||
|
||||
function getDefaultSnapshots(project_created_at: Date | string) {
|
||||
|
||||
const today: DefaultSnapshot = {
|
||||
_id: '___today' as any,
|
||||
name: 'Today',
|
||||
from: fns.startOfDay(Date.now()),
|
||||
to: fns.endOfDay(Date.now()),
|
||||
color: '#FFA600',
|
||||
default: true
|
||||
}
|
||||
|
||||
const lastDay: DefaultSnapshot = {
|
||||
_id: '___lastDay' as any,
|
||||
name: 'Yesterday',
|
||||
from: fns.startOfDay(fns.subDays(Date.now(), 1)),
|
||||
to: fns.endOfDay(fns.subDays(Date.now(), 1)),
|
||||
color: '#FF8531',
|
||||
default: true
|
||||
}
|
||||
|
||||
|
||||
const lastMonth: DefaultSnapshot = {
|
||||
_id: '___lastMonth' as any,
|
||||
name: 'Last Month',
|
||||
from: fns.startOfMonth(fns.subMonths(Date.now(), 1)),
|
||||
to: fns.endOfMonth(fns.subMonths(Date.now(), 1)),
|
||||
color: '#BC5090',
|
||||
default: true
|
||||
}
|
||||
const currentMonth: DefaultSnapshot = {
|
||||
_id: '___currentMonth' as any,
|
||||
name: 'Current Month',
|
||||
from: fns.startOfMonth(Date.now()),
|
||||
to: fns.endOfMonth(Date.now()),
|
||||
color: '#58508D',
|
||||
default: true
|
||||
}
|
||||
|
||||
|
||||
const lastWeek: DefaultSnapshot = {
|
||||
_id: '___lastWeek' as any,
|
||||
name: 'Last Week',
|
||||
from: fns.startOfWeek(fns.subWeeks(Date.now(), 1)),
|
||||
to: fns.endOfWeek(fns.subWeeks(Date.now(), 1)),
|
||||
color: '#3E909D',
|
||||
default: true
|
||||
}
|
||||
|
||||
|
||||
const currentWeek: DefaultSnapshot = {
|
||||
_id: '___currentWeek' as any,
|
||||
name: 'Current Week',
|
||||
from: fns.startOfWeek(Date.now()),
|
||||
to: fns.endOfWeek(Date.now()),
|
||||
color: '#007896',
|
||||
default: true
|
||||
}
|
||||
|
||||
|
||||
const allTime: DefaultSnapshot = {
|
||||
_id: '___allTime' as any,
|
||||
name: 'All Time',
|
||||
from: fns.addMinutes(
|
||||
fns.startOfMonth(new Date(project_created_at.toString())),
|
||||
-new Date().getTimezoneOffset()
|
||||
),
|
||||
to: fns.addMilliseconds(fns.endOfDay(Date.now()), 1),
|
||||
color: '#9362FF',
|
||||
default: true
|
||||
}
|
||||
|
||||
|
||||
const last30Days: DefaultSnapshot = {
|
||||
_id: '___last30days' as any,
|
||||
name: 'Last 30 days',
|
||||
from: fns.startOfDay(fns.subDays(Date.now(), 30)),
|
||||
to: fns.endOfDay(fns.subDays(Date.now(), 0)),
|
||||
color: '#606c38',
|
||||
default: true
|
||||
}
|
||||
|
||||
const last60Days: DefaultSnapshot = {
|
||||
_id: '___last60days' as any,
|
||||
name: 'Last 60 days',
|
||||
from: fns.startOfDay(fns.subDays(Date.now(), 60)),
|
||||
to: fns.endOfDay(fns.subDays(Date.now(), 0)),
|
||||
color: '#bc6c25',
|
||||
default: true
|
||||
}
|
||||
|
||||
const last90Days: DefaultSnapshot = {
|
||||
_id: '___last90days' as any,
|
||||
name: 'Last 90 days',
|
||||
from: fns.startOfDay(fns.subDays(Date.now(), 90)),
|
||||
to: fns.endOfDay(fns.subDays(Date.now(), 0)),
|
||||
color: '#fefae0',
|
||||
default: true
|
||||
}
|
||||
|
||||
|
||||
const snapshotList = [
|
||||
allTime,
|
||||
lastDay, today,
|
||||
lastWeek, currentWeek,
|
||||
lastMonth, currentMonth,
|
||||
last30Days,
|
||||
last60Days, last90Days,
|
||||
]
|
||||
|
||||
return snapshotList;
|
||||
|
||||
}
|
||||
|
||||
export const useSnapshotStore = defineStore('snapshot', () => {
|
||||
|
||||
const snapshots = shallowRef<GenericSnapshot[]>([]);
|
||||
const activeSnapshot = shallowRef<GenericSnapshot>();
|
||||
|
||||
async function fetchSnapshots(options?: { activateLast: boolean }) {
|
||||
snapshots.value = [];
|
||||
activeSnapshot.value = undefined;
|
||||
await nextTick();
|
||||
const res = await useAuthFetchSync<TProjectSnapshot[]>('/api/snapshot/list');
|
||||
snapshots.value = [
|
||||
...getDefaultSnapshots(new Date(2024, 1, 1)),
|
||||
...res
|
||||
];
|
||||
if (options?.activateLast) {
|
||||
activeSnapshot.value = snapshots.value.at(-1);
|
||||
} else {
|
||||
activeSnapshot.value = snapshots.value[7];
|
||||
}
|
||||
}
|
||||
|
||||
function setActive(snapshot_id: string) {
|
||||
activeSnapshot.value = snapshots.value.find(e => snapshot_id === e._id.toString());
|
||||
}
|
||||
|
||||
const from = computed(() => {
|
||||
if (!activeSnapshot.value) return;
|
||||
return new Date(activeSnapshot.value.from).getTime()
|
||||
});
|
||||
const to = computed(() => {
|
||||
if (!activeSnapshot.value) return;
|
||||
return new Date(activeSnapshot.value.to).getTime()
|
||||
});
|
||||
|
||||
const duration = computed(() => {
|
||||
if (!activeSnapshot.value) return 0;
|
||||
const from = new Date(activeSnapshot.value.from).getTime();
|
||||
const to = new Date(activeSnapshot.value.to).getTime() + 1000;
|
||||
return fns.differenceInDays(to, from);
|
||||
});
|
||||
|
||||
return {
|
||||
snapshots,
|
||||
activeSnapshot,
|
||||
fetchSnapshots,
|
||||
setActive,
|
||||
duration,
|
||||
from, to
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user