update guests logic + fix pdf

This commit is contained in:
Emily
2025-02-10 16:28:34 +01:00
parent abc485a9ef
commit 346eecc928
25 changed files with 81 additions and 51 deletions

View File

@@ -2,7 +2,7 @@
import type { TApiSettings } from '@schema/ApiSettingsSchema';
import type { SettingsTemplateEntry } from './Template.vue';
const { project } = useProject();
const { project, isGuest } = useProject();
const entries: SettingsTemplateEntry[] = [
{ id: 'acodes', title: 'Appsumo codes', text: 'Redeem appsumo codes' },
@@ -39,7 +39,7 @@ async function redeemCode() {
<template>
<SettingsTemplate :entries="entries" :key="project?.name || 'NONE'">
<SettingsTemplate v-if="!isGuest" :entries="entries" :key="project?.name || 'NONE'">
<template #acodes>
<div class="flex items-center gap-4">
<LyxUiInput class="w-full px-4 py-2" placeholder="Appsumo code" v-model="currentCode"></LyxUiInput>
@@ -58,4 +58,9 @@ async function redeemCode() {
</div>
</template>
</SettingsTemplate>
<div v-if="isGuest" class="text-lyx-text-darker flex w-full h-full justify-center mt-20">
Guests cannot view billing
</div>
</template>

View File

@@ -2,6 +2,9 @@
import DeleteDomainData from '../dialog/DeleteDomainData.vue';
import type { SettingsTemplateEntry } from './Template.vue';
const { isGuest } = useProject();
const entries: SettingsTemplateEntry[] = [
{ id: 'delete_dns', title: 'Delete domain data', text: 'Delete data of a specific domain from this project' },
{ id: 'delete_data', title: 'Delete project data', text: 'Delete all data from this project' },
@@ -105,7 +108,7 @@ const sessionsLabel = computed(() => {
<div class="flex flex-col">
<!-- <div class="text-[.9rem] text-lyx-text-darker"> Select a domain </div> -->
<USelectMenu placeholder="Select a domain" :uiMenu="{
<USelectMenu v-if="!isGuest" placeholder="Select a domain" :uiMenu="{
select: 'bg-lyx-lightmode-widget-light !ring-lyx-lightmode-widget dark:!bg-lyx-widget-light !shadow-none focus:!ring-lyx-widget-lighter dark:!ring-lyx-widget-lighter',
base: '!bg-lyx-lightmode-widget dark:!bg-lyx-widget',
option: {
@@ -114,6 +117,8 @@ const sessionsLabel = computed(() => {
}
}" :options="domains.data.value ?? []" v-model="selectedDomain"></USelectMenu>
<div v-if="isGuest" class="text-lyx-text-darker"> Guests cannot delete data</div>
<div v-if="selectedDomain" class="flex flex-col gap-2 mt-4">
<div class="text-[.9rem] text-lyx-text-dark"> Select data to delete </div>
@@ -141,7 +146,7 @@ const sessionsLabel = computed(() => {
</template>
<template #delete_data>
<div
<div v-if="!isGuest"
class="outline rounded-lg w-full px-8 py-4 flex flex-col gap-4 outline-[1px] outline-[#541c15] bg-lyx-lightmode-widget-light dark:bg-[#1e1412]">
<div class="poppins font-semibold"> This operation will reset this project to it's initial state (0
visits 0 events 0 sessions) </div>
@@ -151,6 +156,7 @@ const sessionsLabel = computed(() => {
</div>
</div>
<div v-if="isGuest" class="text-lyx-text-darker"> Guests cannot delete data</div>
</template>
</SettingsTemplate>
</template>

View File

@@ -156,21 +156,29 @@ function copyProjectId() {
<template>
<SettingsTemplate :entries="entries" :key="project?.name || 'NONE'">
<template #pname>
<div class="flex flex-col gap-2">
<div class="flex items-center gap-4">
<LyxUiInput class="w-full px-4 py-2" :disabled="isGuest" v-model="projectNameInputVal"></LyxUiInput>
<LyxUiButton v-if="!isGuest" @click="changeProjectName()" :disabled="!canChange" type="primary"> Change
<LyxUiButton v-if="!isGuest" @click="changeProjectName()" :disabled="!canChange" type="primary">
Change
</LyxUiButton>
</div>
<div v-if="isGuest" class="text-lyx-text-darker"> *Guests cannot change project name </div>
</div>
</template>
<template #api>
<div class="flex items-center gap-4" v-if="apiKeys && apiKeys.length < 5">
<LyxUiInput class="grow px-4 py-2" :disabled="isGuest" placeholder="ApiKeyName" v-model="newApiKeyName">
<div class="flex flex-col gap-2" v-if="apiKeys && apiKeys.length < 5">
<div class="flex items-center gap-4">
<LyxUiInput class="grow px-4 py-2" :disabled="isGuest" placeholder="ApiKeyName"
v-model="newApiKeyName">
</LyxUiInput>
<LyxUiButton v-if="!isGuest" @click="createApiKey()" :disabled="newApiKeyName.length < 3"
type="primary">
<i class="far fa-plus"></i>
</LyxUiButton>
</div>
<div v-if="isGuest" class="text-lyx-text-darker"> *Guests cannot manage api keys </div>
</div>
<LyxUiCard v-if="apiKeys && apiKeys.length > 0" class="w-full flex flex-col gap-4 items-center mt-4">
<div v-for="apiKey of apiKeys" class="flex flex-col w-full">
@@ -212,6 +220,7 @@ function copyProjectId() {
Delete project
</LyxUiButton>
</div>
<div v-if="isGuest"> *Guests cannot delete project </div>
</template>
</SettingsTemplate>
</template>

View File

@@ -123,7 +123,7 @@ const { showDrawer } = useDrawer();
<i class="fas fa-spinner text-[2rem] text-accent animate-[spin_1s_linear_infinite] duration-500"></i>
</div>
<SettingsTemplate v-if="!invoicesPending && !planPending" :entries="entries">
<SettingsTemplate v-if="!invoicesPending && !planPending && !isGuest" :entries="entries">
<template #info>
<div v-if="!isGuest">
<div class="flex flex-col gap-4">
@@ -267,6 +267,10 @@ const { showDrawer } = useDrawer();
</CardTitled>
</template>
</SettingsTemplate>
<div v-if="isGuest" class="text-lyx-text-darker flex w-full h-full justify-center mt-20">
Guests cannot view billing
</div>
</div>

View File

@@ -98,6 +98,7 @@ const entries: SettingsTemplateEntry[] = [
User should have been registered to Litlyx
</div>
</div>
<div v-if="isGuest" class="text-lyx-text-darker"> Guests cannot add members</div>
</template>
<template #members>

View File

@@ -398,24 +398,29 @@ async function clearAllChats() {
<div :class="{ '!text-green-500': debugModeAi }" class="cursor-pointer text-red-500 w-fit"
v-if="userRoles.isAdmin.value" @click="debugModeAi = !debugModeAi"> Debug mode </div>
<div class="flex justify-between items-center pt-3">
<div class="flex pt-3 px-4">
<div class="flex items-center gap-2">
<div class="bg-accent w-5 h-5 rounded-full animate-pulse">
</div>
<div class="manrope font-semibold text-lyx-lightmode-text dark:text-text-dirty"> {{
chatsRemaining }} messages left
<!-- <div class="bg-accent w-4 h-4 rounded-full animate-pulse">
</div> -->
<div class="manrope font-semibold text-lyx-lightmode-text dark:text-text-dirty">
{{ chatsRemaining }} messages left
</div>
</div>
<LyxUiButton v-if="!selfhosted" type="primary" class="text-[.9rem] text-center " @click="showDrawer('PRICING')">
<div class="grow"></div>
<LyxUiButton v-if="!selfhosted" type="primary" class="text-[.9rem] text-center "
@click="showDrawer('PRICING')">
Upgrade
</LyxUiButton>
</div>
<div class="flex items-center gap-4">
<div class="dark:bg-lyx-widget-light bg-lyx-lightmode-widget-light h-[1px]"></div>
<div class="flex items-center gap-4 px-4 mt-4">
<div class="poppins font-semibold text-[1.1rem]"> History </div>
<div class="grow"></div>
<LyxUiButton v-if="chatsList && chatsList.length > 0" @click="clearAllChats()" type="secondary"
class="text-center text-[.8rem]">
Clear all
Clear all chats
</LyxUiButton>
</div>

View File

@@ -16,7 +16,7 @@ const canDownload = computed(() => {
const metricsInfo = ref<number>(0);
const columns = [
{ key: 'website', label: 'Website', sortable: true },
{ key: 'website', label: 'Domain', sortable: true },
{ key: 'page', label: 'Page', sortable: true },
{ key: 'referrer', label: 'Referrer', sortable: true },
{ key: 'browser', label: 'Browser', sortable: true },

View File

@@ -71,7 +71,7 @@ async function createProject() {
<div class="flex flex-col items-center justify-center pt-[12rem] gap-12 relative z-[10]">
<div class="text-[3rem] font-semibold text-center text-lyx-lightmode-text dark:text-lyx-text">
Create your {{ isFirstProject ? 'first' : '' }} project
Create {{ isFirstProject ? '' : 'a new' }} {{ isFirstProject ? 'your first' : '' }} project
</div>
<div v-if="isFirstProject" class="text-[1.5rem]">

View File

@@ -16,7 +16,7 @@ const items = [
</script>
<template>
<div class="lg:px-10 lg:py-8 h-dvh overflow-y-auto overflow-x-hidden hide-scrollbars">
<div class="lg:px-10 lg:py-8 h-dvh overflow-y-auto overflow-x-hidden hide-scrollbars !pb-[10rem]">
<div class="poppins font-semibold text-[1.3rem] lg:px-0 px-4 lg:py-0 py-4"> Settings </div>

View File

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -3,7 +3,7 @@ import StripeService from '~/server/services/StripeService';
export default defineEventHandler(async event => {
const data = await getRequestDataOld(event, { requireSchema: false, allowLitlyx: false });
const data = await getRequestData(event, []);
if (!data) return;
const { project } = data;

View File

@@ -12,7 +12,7 @@ export type InvoiceData = {
}
export default defineEventHandler(async event => {
const data = await getRequestDataOld(event, { requireSchema: false, allowLitlyx: false });
const data = await getRequestData(event, []);
if (!data) return;
const { project, pid } = data;

View File

@@ -22,7 +22,7 @@ function getPlanToActivate(current_plan_id: number) {
export default defineEventHandler(async event => {
const data = await getRequestDataOld(event, { requireSchema: false, allowGuests: false, allowLitlyx: false });
const data = await getRequestData(event, []);
if (!data) return;
const { project, pid, user } = data;

View File

@@ -4,7 +4,7 @@ import StripeService from '~/server/services/StripeService';
export default defineEventHandler(async event => {
const data = await getRequestDataOld(event, { requireSchema: false, allowLitlyx: false });
const data = await getRequestData(event, []);
if (!data) return;
const { project } = data;

View File

@@ -33,17 +33,19 @@ function formatNumberK(value: string | number, decimals: number = 1) {
const LINE_SPACING = 0.5;
const resourcePath = process.env.MODE === 'TEST' ? './public/pdf/' : '../public/pdf/';
function createPdf(data: PDFGenerationData) {
const pdf = new pdfkit({ size: 'A4', margins: { top: 50, bottom: 50, left: 50, right: 50 }, });
pdf.fillColor('#ffffff').rect(0, 0, pdf.page.width, pdf.page.height).fill('#000000');
pdf.font('./server/pdf/pdf_fonts/Poppins-Bold.ttf').fontSize(16).fillColor('#ffffff');
pdf.font(resourcePath + 'pdf_fonts/Poppins-Bold.ttf').fontSize(16).fillColor('#ffffff');
pdf.text(`Project name: ${data.projectName}`, { align: 'left' }).moveDown(LINE_SPACING);
pdf.text(`Timeframe name: ${data.snapshotName}`, { align: 'left' }).moveDown(LINE_SPACING);
pdf.font('./server/pdf/pdf_fonts/Poppins-Regular.ttf').fontSize(12).fillColor('#ffffff')
pdf.font(resourcePath + 'pdf_fonts/Poppins-Regular.ttf').fontSize(12).fillColor('#ffffff')
pdf.text(`Total visits: ${data.totalVisits}`, { align: 'left' }).moveDown(LINE_SPACING);
pdf.text(`Average visits per day: ${data.avgVisitsDay}`, { align: 'left' }).moveDown(LINE_SPACING);
@@ -64,16 +66,16 @@ function createPdf(data: PDFGenerationData) {
pdf.text('Average growth:', { align: 'left' }).moveDown(LINE_SPACING);
pdf.text(`${data.avgGrowthText}`, { align: 'left' }).moveDown(LINE_SPACING);
pdf.font('./server/pdf/pdf_fonts/Poppins-Italic.ttf')
pdf.font(resourcePath + 'pdf_fonts/Poppins-Italic.ttf')
.text('This gives you an idea of the average growth your website is experiencing over time.', { align: 'left' })
.moveDown(LINE_SPACING);
pdf.font('./server/pdf/pdf_fonts/Poppins-Regular.ttf')
pdf.font(resourcePath + 'pdf_fonts/Poppins-Regular.ttf')
.fontSize(10)
.fillColor('#ffffff')
.text('Created with Litlyx.com', 50, 760, { align: 'center' });
pdf.image('./server/pdf/pdf_images/logo.png', 460, 700, { width: 100 });
pdf.image(resourcePath + 'pdf_images/logo.png', 460, 700, { width: 100 });
pdf.end();
return pdf;

View File

@@ -3,7 +3,7 @@ import StripeService from '~/server/services/StripeService';
export default defineEventHandler(async event => {
const data = await getRequestDataOld(event, { requireSchema: false, allowLitlyx: false });
const data = await getRequestData(event, []);
if (!data) return;
const { project, project_id } = data;

View File

@@ -3,11 +3,10 @@ import { EventModel } from "@schema/metrics/EventSchema";
import { SessionModel } from "@schema/metrics/SessionSchema";
import { VisitModel } from "@schema/metrics/VisitSchema";
import { Types } from "mongoose";
import { getRequestDataOld } from "~/server/utils/getRequestData";
export default defineEventHandler(async event => {
const data = await getRequestDataOld(event, { requireSchema: false });
const data = await getRequestData(event, []);
if (!data) return;
const { project_id } = data;

View File

@@ -3,11 +3,10 @@ import { EventModel } from "@schema/metrics/EventSchema";
import { SessionModel } from "@schema/metrics/SessionSchema";
import { VisitModel } from "@schema/metrics/VisitSchema";
import { Types } from "mongoose";
import { getRequestDataOld } from "~/server/utils/getRequestData";
export default defineEventHandler(async event => {
const data = await getRequestDataOld(event, { requireSchema: false });
const data = await getRequestData(event, []);
if (!data) return;
const { project_id } = data;