mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-10 15:58:38 +01:00
use new mail service in dashboard
This commit is contained in:
@@ -44,8 +44,7 @@ export default defineNuxtConfig({
|
|||||||
AI_ORG: process.env.AI_ORG,
|
AI_ORG: process.env.AI_ORG,
|
||||||
AI_PROJECT: process.env.AI_PROJECT,
|
AI_PROJECT: process.env.AI_PROJECT,
|
||||||
AI_KEY: process.env.AI_KEY,
|
AI_KEY: process.env.AI_KEY,
|
||||||
EMAIL_SERVICE: process.env.EMAIL_SERVICE,
|
EMAIL_SECRET: process.env.EMAIL_SECRET,
|
||||||
BREVO_API_KEY: process.env.BREVO_API_KEY,
|
|
||||||
AUTH_JWT_SECRET: process.env.AUTH_JWT_SECRET,
|
AUTH_JWT_SECRET: process.env.AUTH_JWT_SECRET,
|
||||||
GOOGLE_AUTH_CLIENT_ID: process.env.GOOGLE_AUTH_CLIENT_ID,
|
GOOGLE_AUTH_CLIENT_ID: process.env.GOOGLE_AUTH_CLIENT_ID,
|
||||||
GOOGLE_AUTH_CLIENT_SECRET: process.env.GOOGLE_AUTH_CLIENT_SECRET,
|
GOOGLE_AUTH_CLIENT_SECRET: process.env.GOOGLE_AUTH_CLIENT_SECRET,
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
import { createUserJwt, readRegisterJwt } from '~/server/AuthManager';
|
import { createUserJwt, readRegisterJwt } from '~/server/AuthManager';
|
||||||
import { UserModel } from '@schema/UserSchema';
|
import { UserModel } from '@schema/UserSchema';
|
||||||
import { PasswordModel } from '@schema/PasswordSchema';
|
import { PasswordModel } from '@schema/PasswordSchema';
|
||||||
// import EmailService from '@services/EmailService';
|
import { EmailService } from '@services/EmailService';
|
||||||
|
import { EmailServiceHelper } from '~/server/services/EmailServiceHelper';
|
||||||
|
|
||||||
export default defineEventHandler(async event => {
|
export default defineEventHandler(async event => {
|
||||||
|
|
||||||
@@ -14,7 +15,10 @@ export default defineEventHandler(async event => {
|
|||||||
try {
|
try {
|
||||||
await PasswordModel.create({ email: data.email, password: data.password })
|
await PasswordModel.create({ email: data.email, password: data.password })
|
||||||
await UserModel.create({ email: data.email, given_name: '', name: 'EmailLogin', locale: '', picture: '', created_at: Date.now() });
|
await UserModel.create({ email: data.email, given_name: '', name: 'EmailLogin', locale: '', picture: '', created_at: Date.now() });
|
||||||
// setImmediate(() => { EmailService.sendWelcomeEmail(data.email); });
|
setImmediate(() => {
|
||||||
|
const emailData = EmailService.getEmailServerInfo('welcome', { target: data.email });
|
||||||
|
EmailServiceHelper.sendEmail(emailData);
|
||||||
|
});
|
||||||
const jwt = createUserJwt({ email: data.email, name: 'EmailLogin' });
|
const jwt = createUserJwt({ email: data.email, name: 'EmailLogin' });
|
||||||
return sendRedirect(event, `https://dashboard.litlyx.com/jwt_login?jwt_login=${jwt}`);
|
return sendRedirect(event, `https://dashboard.litlyx.com/jwt_login?jwt_login=${jwt}`);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
import { OAuth2Client } from 'google-auth-library';
|
import { OAuth2Client } from 'google-auth-library';
|
||||||
import { createUserJwt } from '~/server/AuthManager';
|
import { createUserJwt } from '~/server/AuthManager';
|
||||||
import { UserModel } from '@schema/UserSchema';
|
import { UserModel } from '@schema/UserSchema';
|
||||||
// import EmailService from '@services/EmailService';
|
import { EmailService } from '@services/EmailService';
|
||||||
|
import { EmailServiceHelper } from '~/server/services/EmailServiceHelper';
|
||||||
|
|
||||||
const { GOOGLE_AUTH_CLIENT_SECRET, GOOGLE_AUTH_CLIENT_ID } = useRuntimeConfig()
|
const { GOOGLE_AUTH_CLIENT_SECRET, GOOGLE_AUTH_CLIENT_ID } = useRuntimeConfig()
|
||||||
|
|
||||||
@@ -58,10 +59,12 @@ export default defineEventHandler(async event => {
|
|||||||
|
|
||||||
const savedUser = await newUser.save();
|
const savedUser = await newUser.save();
|
||||||
|
|
||||||
// setImmediate(() => {
|
setImmediate(() => {
|
||||||
// console.log('SENDING WELCOME EMAIL TO', payload.email);
|
console.log('SENDING WELCOME EMAIL TO', payload.email);
|
||||||
// if (payload.email) EmailService.sendWelcomeEmail(payload.email);
|
if (!payload.email) return;
|
||||||
// });
|
const emailData = EmailService.getEmailServerInfo('welcome', { target: payload.email });
|
||||||
|
EmailServiceHelper.sendEmail(emailData);
|
||||||
|
});
|
||||||
|
|
||||||
return { error: false, access_token: createUserJwt({ email: savedUser.email, name: savedUser.name }) }
|
return { error: false, access_token: createUserJwt({ email: savedUser.email, name: savedUser.name }) }
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
|
||||||
import { createRegisterJwt, createUserJwt } from '~/server/AuthManager';
|
import { createRegisterJwt } from '~/server/AuthManager';
|
||||||
import { UserModel } from '@schema/UserSchema';
|
import { UserModel } from '@schema/UserSchema';
|
||||||
import { RegisterModel } from '@schema/RegisterSchema';
|
import { RegisterModel } from '@schema/RegisterSchema';
|
||||||
// import EmailService from '@services/EmailService';
|
import { EmailService } from '@services/EmailService';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
|
import { EmailServiceHelper } from '~/server/services/EmailServiceHelper';
|
||||||
|
|
||||||
function canRegister(email: string, password: string) {
|
function canRegister(email: string, password: string) {
|
||||||
if (email.length == 0) return false;
|
if (email.length == 0) return false;
|
||||||
@@ -33,9 +34,10 @@ export default defineEventHandler(async event => {
|
|||||||
|
|
||||||
await RegisterModel.create({ email, password: hashedPassword });
|
await RegisterModel.create({ email, password: hashedPassword });
|
||||||
|
|
||||||
// setImmediate(() => {
|
setImmediate(() => {
|
||||||
// EmailService.sendConfirmEmail(email, `https://dashboard.litlyx.com/api/auth/confirm_email?register_code=${jwt}`);
|
const emailData = EmailService.getEmailServerInfo('confirm', { target: email, link: `https://dashboard.litlyx.com/api/auth/confirm_email?register_code=${jwt}` });
|
||||||
// });
|
EmailServiceHelper.sendEmail(emailData);
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
error: false,
|
error: false,
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
|
|
||||||
import { createUserJwt } from '~/server/AuthManager';
|
|
||||||
import { UserModel } from '@schema/UserSchema';
|
|
||||||
import EmailService from '@services/EmailService';
|
|
||||||
|
|
||||||
const config = useRuntimeConfig();
|
|
||||||
|
|
||||||
export default defineEventHandler(async event => {
|
|
||||||
|
|
||||||
const { code } = getQuery(event);
|
|
||||||
console.log('CODE', code);
|
|
||||||
|
|
||||||
const redirect_uri = 'http://127.0.0.1:3000'
|
|
||||||
|
|
||||||
const res = await fetch(`https://github.com/login/oauth/access_token?client_id=${config.GITHUB_AUTH_CLIENT_ID}&client_secret=${config.GITHUB_AUTH_CLIENT_SECRET}&code=${code}&redirect_url=${redirect_uri}`, {
|
|
||||||
headers: {
|
|
||||||
"Accept": "application/json",
|
|
||||||
"Accept-Encoding": "application/json",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await res.json();
|
|
||||||
|
|
||||||
const access_token = data.access_token;
|
|
||||||
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
return sendRedirect(event,`http://127.0.0.1:3000/login?github_access_token=${access_token}`)
|
|
||||||
|
|
||||||
|
|
||||||
// const origin = event.headers.get('origin');
|
|
||||||
|
|
||||||
// const tokenResponse = await client.getToken({
|
|
||||||
// code: body.code,
|
|
||||||
// redirect_uri: origin || ''
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const tokens = tokenResponse.tokens;
|
|
||||||
|
|
||||||
// const ticket = await client.verifyIdToken({
|
|
||||||
// idToken: tokens.id_token || '',
|
|
||||||
// audience: GOOGLE_AUTH_CLIENT_ID,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const payload = ticket.getPayload();
|
|
||||||
// if (!payload) return { error: true, access_token: '' };
|
|
||||||
|
|
||||||
|
|
||||||
// const user = await UserModel.findOne({ email: payload.email });
|
|
||||||
|
|
||||||
// if (user) return { error: false, access_token: createUserJwt({ email: user.email, name: user.name }) }
|
|
||||||
|
|
||||||
|
|
||||||
// const newUser = new UserModel({
|
|
||||||
// email: payload.email,
|
|
||||||
// given_name: payload.given_name,
|
|
||||||
// name: payload.name,
|
|
||||||
// locale: payload.locale,
|
|
||||||
// picture: payload.picture,
|
|
||||||
// created_at: Date.now()
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const savedUser = await newUser.save();
|
|
||||||
|
|
||||||
// setImmediate(() => {
|
|
||||||
// console.log('SENDING WELCOME EMAIL TO', payload.email);
|
|
||||||
// if (payload.email) EmailService.sendWelcomeEmail(payload.email);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return { error: false, access_token: createUserJwt({ email: savedUser.email, name: savedUser.name }) }
|
|
||||||
|
|
||||||
});
|
|
||||||
@@ -4,9 +4,9 @@ import type Event from 'stripe';
|
|||||||
import { ProjectModel } from '@schema/project/ProjectSchema';
|
import { ProjectModel } from '@schema/project/ProjectSchema';
|
||||||
import { PREMIUM_DATA, PREMIUM_PLAN, getPlanFromId, getPlanFromPrice, getPlanFromTag } from '@data/PREMIUM';
|
import { PREMIUM_DATA, PREMIUM_PLAN, getPlanFromId, getPlanFromPrice, getPlanFromTag } from '@data/PREMIUM';
|
||||||
import { ProjectLimitModel } from '@schema/project/ProjectsLimits';
|
import { ProjectLimitModel } from '@schema/project/ProjectsLimits';
|
||||||
// import EmailService from '@services/EmailService'
|
import { EmailService } from '@services/EmailService'
|
||||||
import { UserModel } from '@schema/UserSchema';
|
import { UserModel } from '@schema/UserSchema';
|
||||||
|
import { EmailServiceHelper } from '~/server/services/EmailServiceHelper';
|
||||||
|
|
||||||
|
|
||||||
async function addSubscriptionToProject(project_id: string, plan: PREMIUM_DATA, subscription_id: string, current_period_start: number, current_period_end: number) {
|
async function addSubscriptionToProject(project_id: string, plan: PREMIUM_DATA, subscription_id: string, current_period_start: number, current_period_end: number) {
|
||||||
@@ -93,9 +93,10 @@ async function onPaymentOnetimeSuccess(event: Event.PaymentIntentSucceededEvent)
|
|||||||
const user = await UserModel.findOne({ _id: project.owner });
|
const user = await UserModel.findOne({ _id: project.owner });
|
||||||
if (!user) return { ok: false, error: 'USER NOT EXIST FOR PROJECT' + project.id }
|
if (!user) return { ok: false, error: 'USER NOT EXIST FOR PROJECT' + project.id }
|
||||||
|
|
||||||
// setTimeout(() => {
|
setTimeout(() => {
|
||||||
// EmailService.sendPurchaseEmail(user.email, project.name);
|
const emailData = EmailService.getEmailServerInfo('purchase', { target: user.email, projectName: project.name });
|
||||||
// }, 1);
|
EmailServiceHelper.sendEmail(emailData);
|
||||||
|
}, 1);
|
||||||
|
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
}
|
}
|
||||||
@@ -140,10 +141,11 @@ async function onPaymentSuccess(event: Event.InvoicePaidEvent) {
|
|||||||
const user = await UserModel.findOne({ _id: project.owner });
|
const user = await UserModel.findOne({ _id: project.owner });
|
||||||
if (!user) return { ok: false, error: 'USER NOT EXIST FOR PROJECT' + project.id }
|
if (!user) return { ok: false, error: 'USER NOT EXIST FOR PROJECT' + project.id }
|
||||||
|
|
||||||
// setTimeout(() => {
|
setTimeout(() => {
|
||||||
// if (PLAN.ID == 0) return;
|
if (PLAN.ID == 0) return;
|
||||||
// if (isNewSubscription) EmailService.sendPurchaseEmail(user.email, project.name);
|
const emailData = EmailService.getEmailServerInfo('purchase', { target: user.email, projectName: project.name });
|
||||||
// }, 1);
|
EmailServiceHelper.sendEmail(emailData);
|
||||||
|
}, 1);
|
||||||
|
|
||||||
|
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { VisitModel } from "@schema/metrics/VisitSchema";
|
import { VisitModel } from "@schema/metrics/VisitSchema";
|
||||||
import { Redis } from "~/server/services/CacheService";
|
import { Redis } from "~/server/services/CacheService";
|
||||||
import { executeTimelineAggregation } from "~/server/services/TimelineService";
|
import { executeAdvancedTimelineAggregation } from "~/server/services/TimelineService";
|
||||||
|
|
||||||
export default defineEventHandler(async event => {
|
export default defineEventHandler(async event => {
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ export default defineEventHandler(async event => {
|
|||||||
const cacheExp = 60;
|
const cacheExp = 60;
|
||||||
|
|
||||||
return await Redis.useCacheV2(cacheKey, cacheExp, async () => {
|
return await Redis.useCacheV2(cacheKey, cacheExp, async () => {
|
||||||
const timelineData = await executeTimelineAggregation({
|
const timelineData = await executeAdvancedTimelineAggregation({
|
||||||
projectId: project_id,
|
projectId: project_id,
|
||||||
model: VisitModel,
|
model: VisitModel,
|
||||||
from, to, slice, timeOffset, domain
|
from, to, slice, timeOffset, domain
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { PasswordModel } from '@schema/PasswordSchema';
|
import { PasswordModel } from '@schema/PasswordSchema';
|
||||||
// import EmailService from '@services/EmailService'
|
import { EmailService } from '@services/EmailService'
|
||||||
|
import { EmailServiceHelper } from '~/server/services/EmailServiceHelper';
|
||||||
|
|
||||||
export default defineEventHandler(async event => {
|
export default defineEventHandler(async event => {
|
||||||
|
|
||||||
@@ -19,7 +20,8 @@ export default defineEventHandler(async event => {
|
|||||||
target.password = hashedPassword;
|
target.password = hashedPassword;
|
||||||
await target.save();
|
await target.save();
|
||||||
|
|
||||||
// await EmailService.sendResetPasswordEmail(email, newPass);
|
const emailData = EmailService.getEmailServerInfo('reset_password', { target: email, newPassword: newPass });
|
||||||
|
EmailServiceHelper.sendEmail(emailData);
|
||||||
|
|
||||||
return { error: false, message: 'Password changed' }
|
return { error: false, message: 'Password changed' }
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import mongoose from "mongoose";
|
import mongoose from "mongoose";
|
||||||
import { Redis } from "~/server/services/CacheService";
|
import { Redis } from "~/server/services/CacheService";
|
||||||
// import EmailService from '@services/EmailService';
|
|
||||||
import StripeService from '~/server/services/StripeService';
|
import StripeService from '~/server/services/StripeService';
|
||||||
import { logger } from "./Logger";
|
import { logger } from "./Logger";
|
||||||
|
|
||||||
@@ -14,12 +13,6 @@ export default async () => {
|
|||||||
|
|
||||||
logger.info('[SERVER] Initializing');
|
logger.info('[SERVER] Initializing');
|
||||||
|
|
||||||
// if (config.EMAIL_SERVICE) {
|
|
||||||
// EmailService.init(config.BREVO_API_KEY);
|
|
||||||
// logger.info('[EMAIL] Initialized');
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
if (config.STRIPE_SECRET) {
|
if (config.STRIPE_SECRET) {
|
||||||
StripeService.init(config.STRIPE_SECRET, config.STRIPE_WH_SECRET, false);
|
StripeService.init(config.STRIPE_SECRET, config.STRIPE_WH_SECRET, false);
|
||||||
logger.info('[STRIPE] Initialized');
|
logger.info('[STRIPE] Initialized');
|
||||||
@@ -41,13 +34,8 @@ export default async () => {
|
|||||||
|
|
||||||
logger.info('[SERVER] Completed');
|
logger.info('[SERVER] Completed');
|
||||||
|
|
||||||
logger.warn('[ANOMALY LOOP] Disabled');
|
|
||||||
|
|
||||||
|
|
||||||
logger.warn(`[SELFHOSTED_SERVER] ${config.SELFHOSTED}`);
|
logger.warn(`[SELFHOSTED_SERVER] ${config.SELFHOSTED}`);
|
||||||
logger.warn(`[SELFHOSTED_CLIENT] ${config.public.SELFHOSTED}`);
|
logger.warn(`[SELFHOSTED_CLIENT] ${config.public.SELFHOSTED}`);
|
||||||
logger.warn(`[AUTH] ${config.public.AUTH_MODE}`);
|
logger.warn(`[AUTH] ${config.public.AUTH_MODE}`);
|
||||||
|
|
||||||
// anomalyLoop();
|
|
||||||
|
|
||||||
};
|
};
|
||||||
18
dashboard/server/services/EmailServiceHelper.ts
Normal file
18
dashboard/server/services/EmailServiceHelper.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
import { EmailServerInfo } from '@services/EmailService'
|
||||||
|
|
||||||
|
const { EMAIL_SECRET } = useRuntimeConfig();
|
||||||
|
|
||||||
|
export class EmailServiceHelper {
|
||||||
|
static async sendEmail(data: EmailServerInfo) {
|
||||||
|
try {
|
||||||
|
await $fetch(data.url, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(data.body),
|
||||||
|
headers: { ...data.headers, 'x-litlyx-token': EMAIL_SECRET }
|
||||||
|
})
|
||||||
|
} catch (ex) {
|
||||||
|
console.error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
dashboard/shared/services/EmailService.ts
Normal file
35
dashboard/shared/services/EmailService.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
const templateMap = {
|
||||||
|
confirm: '/confirm',
|
||||||
|
welcome: '/welcome',
|
||||||
|
purchase: '/purchase',
|
||||||
|
reset_password: '/reset_password',
|
||||||
|
anomaly_domain: '/anomaly/domain',
|
||||||
|
anomaly_visits_events: '/anomaly_visits_events',
|
||||||
|
limit_50: '/limit/50',
|
||||||
|
limit_90: '/limit/90',
|
||||||
|
limit_max: '/limit/max',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type EmailTemplate = keyof typeof templateMap;
|
||||||
|
export type EmailServerInfo = { url: string, body: Record<string, any>, headers: Record<string, string> };
|
||||||
|
|
||||||
|
type EmailData =
|
||||||
|
| { template: 'confirm', data: { target: string, link: string } }
|
||||||
|
| { template: 'welcome', data: { target: string } }
|
||||||
|
| { template: 'purchase', data: { target: string, projectName: string } }
|
||||||
|
| { template: 'reset_password', data: { target: string, newPassword: string } }
|
||||||
|
| { template: 'anomaly_domain', data: { target: string, projectName: string, domains: string[] } }
|
||||||
|
| { template: 'anomaly_visits_events', data: { target: string, projectName: string, data: any[] } }
|
||||||
|
| { template: 'limit_50', data: { target: string, projectName: string } }
|
||||||
|
| { template: 'limit_90', data: { target: string, projectName: string } }
|
||||||
|
| { template: 'limit_max', data: { target: string, projectName: string } };
|
||||||
|
|
||||||
|
export class EmailService {
|
||||||
|
static getEmailServerInfo<T extends EmailTemplate>(template: T, data: Extract<EmailData, { template: T }>['data']): EmailServerInfo {
|
||||||
|
return {
|
||||||
|
url: `https://mail-service.litlyx.com/send${templateMap[template]}`,
|
||||||
|
body: data,
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,16 +19,6 @@ export const PURCHASE_EMAIL = `<!DOCTYPE html>
|
|||||||
|
|
||||||
<p>You can find your current plan details and download your invoices under <strong>Settings > Billing Tab</strong>.</p>
|
<p>You can find your current plan details and download your invoices under <strong>Settings > Billing Tab</strong>.</p>
|
||||||
|
|
||||||
<h3>What does this mean for you?</h3>
|
|
||||||
|
|
||||||
<p>With your upgraded plan, you can now enjoy more data collection, advanced features, and additional benefits to enhance your data analysis capabilities:</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>Access to more storage and increased data limits.</li>
|
|
||||||
<li>Advanced analytics tools like IP-Company Matching, download CSV for your raw data, AI insights, and more.</li>
|
|
||||||
<li>Priority support to help you make the most of your Litlyx experience on Slack or Discord!</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>If you have any questions about your new plan or need assistance, feel free to reach out to our support team at <a href="mailto:help@litlyx.com" style="color: #28a745; text-decoration: none;"><strong>help@litlyx.com</strong></a>. We’re here to help you make the most out of your upgraded plan!</p>
|
<p>If you have any questions about your new plan or need assistance, feel free to reach out to our support team at <a href="mailto:help@litlyx.com" style="color: #28a745; text-decoration: none;"><strong>help@litlyx.com</strong></a>. We’re here to help you make the most out of your upgraded plan!</p>
|
||||||
|
|
||||||
<p><strong>Thank you for using Litlyx every day as your analytics tool and for being a part of our journey.</strong></p>
|
<p><strong>Thank you for using Litlyx every day as your analytics tool and for being a part of our journey.</strong></p>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dashboard:clear-logs": "ts-node scripts/dashboard/clear-logs.ts",
|
"dashboard:clear-logs": "ts-node scripts/dashboard/clear-logs.ts",
|
||||||
"dashboard:shared": "ts-node scripts/dashboard/shared.ts",
|
"dashboard:shared": "ts-node scripts/dashboard/shared.ts",
|
||||||
|
"dashboard:deploy": "ts-node scripts/dashboard/deploy.ts",
|
||||||
"producer:shared": "node scripts/producer/shared.js",
|
"producer:shared": "node scripts/producer/shared.js",
|
||||||
"email:deploy": "ts-node scripts/email/deploy.ts"
|
"email:deploy": "ts-node scripts/email/deploy.ts"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ async function main() {
|
|||||||
if (fs.existsSync(TMP_PATH)) fs.rmSync(TMP_PATH, { force: true, recursive: true });
|
if (fs.existsSync(TMP_PATH)) fs.rmSync(TMP_PATH, { force: true, recursive: true });
|
||||||
fs.ensureDirSync(TMP_PATH);
|
fs.ensureDirSync(TMP_PATH);
|
||||||
|
|
||||||
// console.log('Building');
|
console.log('Building');
|
||||||
// child.execSync(`cd ${LOCAL_PATH} && pnpm i && pnpm run build`)
|
child.execSync(`cd ${LOCAL_PATH} && pnpm i && pnpm run build`)
|
||||||
|
|
||||||
console.log('Creting zip file');
|
console.log('Creting zip file');
|
||||||
const archive = createZip(TMP_PATH + '/' + ZIP_NAME);
|
const archive = createZip(TMP_PATH + '/' + ZIP_NAME);
|
||||||
@@ -71,12 +71,12 @@ async function main() {
|
|||||||
console.log('Extracting remote');
|
console.log('Extracting remote');
|
||||||
await DeployHelper.execute(`cd ${REMOTE_PATH} && unzip ${ZIP_NAME} && rm -r ${ZIP_NAME}`);
|
await DeployHelper.execute(`cd ${REMOTE_PATH} && unzip ${ZIP_NAME} && rm -r ${ZIP_NAME}`);
|
||||||
|
|
||||||
// console.log('Installing remote');
|
console.log('Installing remote');
|
||||||
// await DeployHelper.execute(`cd ${REMOTE_PATH} && /root/.nvm/versions/node/v21.2.0/bin/pnpm i`);
|
await DeployHelper.execute(`cd ${REMOTE_PATH}/.output/server && /root/.nvm/versions/node/v21.2.0/bin/pnpm i`);
|
||||||
|
|
||||||
// await DeployHelper.execute(`cd ${REMOTE_PATH} && /root/.nvm/versions/node/v21.2.0/bin/pm2 start ecosystem.config.js`);
|
console.log('Executing remote');
|
||||||
|
await DeployHelper.execute(`cd ${REMOTE_PATH} && /root/.nvm/versions/node/v21.2.0/bin/pm2 start ecosystem.config.js`);
|
||||||
|
|
||||||
ssh.dispose();
|
ssh.dispose();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { SharedHelper } from "../helpers/shared-helper";
|
import { SharedHelper } from "../helpers/shared-helper";
|
||||||
import path from "path";
|
import path from "node:path";
|
||||||
|
|
||||||
const helper = new SharedHelper(path.join(__dirname, '../../dashboard/shared'))
|
const helper = new SharedHelper(path.join(__dirname, '../../dashboard/shared'))
|
||||||
|
|
||||||
helper.clear();
|
helper.clear();
|
||||||
|
|
||||||
// TODO: Email service as external repo
|
|
||||||
|
|
||||||
helper.create('services');
|
helper.create('services');
|
||||||
helper.copy('services/DateService.ts');
|
helper.copy('services/DateService.ts');
|
||||||
|
helper.copy('services/EmailService.ts');
|
||||||
|
|
||||||
|
|
||||||
helper.create('data');
|
helper.create('data');
|
||||||
|
|||||||
12
scripts/tsconfig.json
Normal file
12
scripts/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "NodeNext",
|
||||||
|
"target": "ESNext"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,193 +1,35 @@
|
|||||||
import { TransactionalEmailsApi, SendSmtpEmail } from '@getbrevo/brevo';
|
const templateMap = {
|
||||||
import { WELCOME_EMAIL } from './email_templates/WelcomeEmail';
|
confirm: '/confirm',
|
||||||
import { LIMIT_50_EMAIL } from './email_templates/Limit50Email';
|
welcome: '/welcome',
|
||||||
import { LIMIT_90_EMAIL } from './email_templates/Limit90Email';
|
purchase: '/purchase',
|
||||||
import { LIMIT_MAX_EMAIL } from './email_templates/LimitMaxEmail';
|
reset_password: '/reset_password',
|
||||||
import { PURCHASE_EMAIL } from './email_templates/PurchaseEmail';
|
anomaly_domain: '/anomaly/domain',
|
||||||
import { ANOMALY_VISITS_EVENTS_EMAIL } from './email_templates/AnomalyUsageEmail';
|
anomaly_visits_events: '/anomaly_visits_events',
|
||||||
import { ANOMALY_DOMAIN_EMAIL } from './email_templates/AnomalyDomainEmail';
|
limit_50: '/limit/50',
|
||||||
import { CONFIRM_EMAIL } from './email_templates/ConfirmEmail';
|
limit_90: '/limit/90',
|
||||||
import { RESET_PASSWORD_EMAIL } from './email_templates/ResetPasswordEmail';
|
limit_max: '/limit/max',
|
||||||
|
} as const;
|
||||||
|
|
||||||
class EmailService {
|
export type EmailTemplate = keyof typeof templateMap;
|
||||||
|
export type EmailServerInfo = { url: string, body: Record<string, any>, headers: Record<string, string> };
|
||||||
|
|
||||||
private apiInstance = new TransactionalEmailsApi();
|
type EmailData =
|
||||||
|
| { template: 'confirm', data: { target: string, link: string } }
|
||||||
|
| { template: 'welcome', data: { target: string } }
|
||||||
|
| { template: 'purchase', data: { target: string, projectName: string } }
|
||||||
|
| { template: 'reset_password', data: { target: string, newPassword: string } }
|
||||||
|
| { template: 'anomaly_domain', data: { target: string, projectName: string, domains: string[] } }
|
||||||
|
| { template: 'anomaly_visits_events', data: { target: string, projectName: string, data: any[] } }
|
||||||
|
| { template: 'limit_50', data: { target: string, projectName: string } }
|
||||||
|
| { template: 'limit_90', data: { target: string, projectName: string } }
|
||||||
|
| { template: 'limit_max', data: { target: string, projectName: string } };
|
||||||
|
|
||||||
init(apiKey: string) {
|
export class EmailService {
|
||||||
this.apiInstance.setApiKey(0, apiKey);
|
static getEmailServerInfo<T extends EmailTemplate>(template: T, data: Extract<EmailData, { template: T }>['data']): EmailServerInfo {
|
||||||
}
|
return {
|
||||||
|
url: `https://mail-service.litlyx.com/send${templateMap[template]}`,
|
||||||
async sendLimitEmail50(target: string, projectName: string) {
|
body: data,
|
||||||
try {
|
headers: { 'Content-Type': 'application/json' }
|
||||||
const sendSmtpEmail = new SendSmtpEmail();
|
};
|
||||||
sendSmtpEmail.subject = "⚡ You've reached 50% limit on Litlyx";
|
|
||||||
sendSmtpEmail.sender = { "name": "Litlyx", "email": "help@litlyx.com" };
|
|
||||||
sendSmtpEmail.to = [{ "email": target }];
|
|
||||||
|
|
||||||
sendSmtpEmail.htmlContent = LIMIT_50_EMAIL
|
|
||||||
.replace(/\[Project Name\]/, projectName)
|
|
||||||
.toString();
|
|
||||||
|
|
||||||
await this.apiInstance.sendTransacEmail(sendSmtpEmail);
|
|
||||||
return true;
|
|
||||||
} catch (ex) {
|
|
||||||
console.error('ERROR SENDING EMAIL', ex);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendLimitEmail90(target: string, projectName: string) {
|
|
||||||
try {
|
|
||||||
const sendSmtpEmail = new SendSmtpEmail();
|
|
||||||
sendSmtpEmail.subject = "⚡ You've reached 90% limit on Litlyx";
|
|
||||||
sendSmtpEmail.sender = { "name": "Litlyx", "email": "help@litlyx.com" };
|
|
||||||
sendSmtpEmail.to = [{ "email": target }];
|
|
||||||
sendSmtpEmail.htmlContent = LIMIT_90_EMAIL
|
|
||||||
.replace(/\[Project Name\]/, projectName)
|
|
||||||
.toString();
|
|
||||||
await this.apiInstance.sendTransacEmail(sendSmtpEmail);
|
|
||||||
return true;
|
|
||||||
} catch (ex) {
|
|
||||||
console.error('ERROR SENDING EMAIL', ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendLimitEmailMax(target: string, projectName: string) {
|
|
||||||
try {
|
|
||||||
const sendSmtpEmail = new SendSmtpEmail();
|
|
||||||
sendSmtpEmail.subject = "🚨 You've reached your limit on Litlyx!";
|
|
||||||
sendSmtpEmail.sender = { "name": "Litlyx", "email": "help@litlyx.com" };
|
|
||||||
sendSmtpEmail.to = [{ "email": target }];
|
|
||||||
sendSmtpEmail.htmlContent = LIMIT_MAX_EMAIL
|
|
||||||
.replace(/\[Project Name\]/, projectName)
|
|
||||||
.toString();
|
|
||||||
await this.apiInstance.sendTransacEmail(sendSmtpEmail);
|
|
||||||
return true;
|
|
||||||
} catch (ex) {
|
|
||||||
console.error('ERROR SENDING EMAIL', ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendWelcomeEmail(target: string) {
|
|
||||||
try {
|
|
||||||
const sendSmtpEmail = new SendSmtpEmail();
|
|
||||||
sendSmtpEmail.subject = "Welcome to Litlyx!";
|
|
||||||
sendSmtpEmail.sender = { "name": "Litlyx", "email": "help@litlyx.com" };
|
|
||||||
sendSmtpEmail.to = [{ "email": target }];
|
|
||||||
sendSmtpEmail.htmlContent = WELCOME_EMAIL;
|
|
||||||
await this.apiInstance.sendTransacEmail(sendSmtpEmail);
|
|
||||||
return true;
|
|
||||||
} catch (ex) {
|
|
||||||
console.error('ERROR SENDING EMAIL', ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendPurchaseEmail(target: string, projectName: string) {
|
|
||||||
try {
|
|
||||||
const sendSmtpEmail = new SendSmtpEmail();
|
|
||||||
sendSmtpEmail.subject = "Thank You for Upgrading Your Litlyx Plan!";
|
|
||||||
sendSmtpEmail.sender = { "name": "Litlyx", "email": "help@litlyx.com" };
|
|
||||||
sendSmtpEmail.to = [{ "email": target }];
|
|
||||||
sendSmtpEmail.htmlContent = PURCHASE_EMAIL
|
|
||||||
.replace(/\[Project Name\]/, projectName)
|
|
||||||
.toString();
|
|
||||||
await this.apiInstance.sendTransacEmail(sendSmtpEmail);
|
|
||||||
return true;
|
|
||||||
} catch (ex) {
|
|
||||||
console.error('ERROR SENDING EMAIL', ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendAnomalyVisitsEventsEmail(target: string, projectName: string,
|
|
||||||
data: {
|
|
||||||
visits: { _id: string, count: number }[],
|
|
||||||
events: { _id: string, count: number }[]
|
|
||||||
}) {
|
|
||||||
try {
|
|
||||||
const sendSmtpEmail = new SendSmtpEmail();
|
|
||||||
sendSmtpEmail.subject = "🔍 Unexpected Activity Detected by our AI";
|
|
||||||
sendSmtpEmail.sender = { "name": "Litlyx", "email": "help@litlyx.com" };
|
|
||||||
sendSmtpEmail.to = [{ "email": target }];
|
|
||||||
sendSmtpEmail.htmlContent = ANOMALY_VISITS_EVENTS_EMAIL
|
|
||||||
.replace(/\[Project Name\]/, projectName)
|
|
||||||
.replace(/\[ENTRIES\]/,
|
|
||||||
[
|
|
||||||
...data.visits.map(e => (`<li> Visits in date ${new Date(e._id).toLocaleDateString('en-EN')} [ ${e.count} ] </li>`)),
|
|
||||||
...data.events.map(e => (`<li> Events in date ${new Date(e._id).toLocaleDateString('en-EN')} [ ${e.count} ] </li>`))
|
|
||||||
]
|
|
||||||
.join('')
|
|
||||||
)
|
|
||||||
.toString();
|
|
||||||
await this.apiInstance.sendTransacEmail(sendSmtpEmail);
|
|
||||||
return true;
|
|
||||||
} catch (ex) {
|
|
||||||
console.error('ERROR SENDING EMAIL', ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendAnomalyDomainEmail(target: string, projectName: string, domains: string[]) {
|
|
||||||
try {
|
|
||||||
const sendSmtpEmail = new SendSmtpEmail();
|
|
||||||
sendSmtpEmail.subject = "🔍 Suspicious dns detected by our AI";
|
|
||||||
sendSmtpEmail.sender = { "name": "Litlyx", "email": "help@litlyx.com" };
|
|
||||||
sendSmtpEmail.to = [{ "email": target }];
|
|
||||||
sendSmtpEmail.htmlContent = ANOMALY_DOMAIN_EMAIL
|
|
||||||
.replace(/\[Project Name\]/, projectName)
|
|
||||||
.replace(/\[CURRENT_DATE\]/, new Date().toLocaleDateString('en-EN'))
|
|
||||||
// .replace(/\[DNS_ENTRIES\]/,
|
|
||||||
// domains.map(e => (`<li> ${e} </li>`)).join('<br>')
|
|
||||||
.replace(/\[DNS_ENTRIES\]/, domains[0])
|
|
||||||
.toString();
|
|
||||||
await this.apiInstance.sendTransacEmail(sendSmtpEmail);
|
|
||||||
return true;
|
|
||||||
} catch (ex) {
|
|
||||||
console.error('ERROR SENDING EMAIL', ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async sendConfirmEmail(target: string, link: string) {
|
|
||||||
try {
|
|
||||||
const sendSmtpEmail = new SendSmtpEmail();
|
|
||||||
sendSmtpEmail.subject = "Confirm your email";
|
|
||||||
sendSmtpEmail.sender = { "name": "Litlyx", "email": "no-reply@litlyx.com" };
|
|
||||||
sendSmtpEmail.to = [{ "email": target }];
|
|
||||||
sendSmtpEmail.htmlContent = CONFIRM_EMAIL
|
|
||||||
.replace(/\[CONFIRM_LINK\]/, link)
|
|
||||||
.toString();
|
|
||||||
await this.apiInstance.sendTransacEmail(sendSmtpEmail);
|
|
||||||
return true;
|
|
||||||
} catch (ex) {
|
|
||||||
console.error('ERROR SENDING EMAIL', ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendResetPasswordEmail(target: string, newPassword: string) {
|
|
||||||
try {
|
|
||||||
const sendSmtpEmail = new SendSmtpEmail();
|
|
||||||
sendSmtpEmail.subject = "Password reset";
|
|
||||||
sendSmtpEmail.sender = { "name": "Litlyx", "email": "no-reply@litlyx.com" };
|
|
||||||
sendSmtpEmail.to = [{ "email": target }];
|
|
||||||
sendSmtpEmail.htmlContent = RESET_PASSWORD_EMAIL
|
|
||||||
.replace(/\[NEW_PASSWORD\]/, newPassword)
|
|
||||||
.toString();
|
|
||||||
await this.apiInstance.sendTransacEmail(sendSmtpEmail);
|
|
||||||
return true;
|
|
||||||
} catch (ex) {
|
|
||||||
console.error('ERROR SENDING EMAIL', ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const instance = new EmailService();
|
|
||||||
export default instance;
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
export const ANOMALY_DOMAIN_EMAIL = `<!DOCTYPE html
|
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html dir="ltr" lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
|
||||||
<meta name="x-apple-disable-message-reformatting" />
|
|
||||||
<!--$-->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body
|
|
||||||
style='background-color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif'>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="max-width:37.5em">
|
|
||||||
<tbody>
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="border:1px solid rgb(0,0,0, 0.1);border-radius:3px;overflow:hidden">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<img src="https://litlyx.com/images/locker2.png"
|
|
||||||
style="display:block;outline:none;border:none;text-decoration:none;max-width:100%"
|
|
||||||
width="620" />
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation" style="padding:20px;padding-bottom:0">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td data-id="__react-email-column">
|
|
||||||
<h1 style="font-size:32px;font-weight:bold;text-align:center">
|
|
||||||
Dear user
|
|
||||||
</h1>
|
|
||||||
<h2 style="font-size:26px;font-weight:bold;text-align:center">
|
|
||||||
Our AI Agent noticed a recent Anomaly on your project on Litlyx.
|
|
||||||
</h2>
|
|
||||||
<p style="font-size:16px;line-height:24px;margin:16px 0">
|
|
||||||
<b>Time: </b> [CURRENT_DATE]
|
|
||||||
<!-- September 7, 2022 at 10:58 AM -->
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
style="font-size:16px;line-height:24px;margin:16px 0;margin-top:-5px">
|
|
||||||
<b>Project: </b> [Project Name]
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
style="font-size:16px;line-height:24px;margin:16px 0;margin-top:-5px">
|
|
||||||
<b>Suspicious DNS: </b> [DNS_ENTRIES]
|
|
||||||
</p>
|
|
||||||
<p style="font-size:16px;line-height:24px;margin:16px 0">
|
|
||||||
If this was you, there's nothing else you
|
|
||||||
need to do.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation" style="padding:20px;padding-top:0">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td colspan="2" data-id="__react-email-column"
|
|
||||||
style="display:flex;justify-content:center;width:100%">
|
|
||||||
<a style="line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px;background-color:#5680f8;border-radius:3px;color:#FFF;font-weight:bold;border:1px solid rgb(0,0,0, 0.1);cursor:pointer;padding:12px 30px 12px 30px"
|
|
||||||
target="_blank" href="https://dashboard.litlyx.com"><span></span><span
|
|
||||||
style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:9px">
|
|
||||||
Go to Dashboard</span><span></span></a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation" style="padding:20px;padding-bottom:0">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td data-id="__react-email-column">
|
|
||||||
<h3>If this wasn't you..</h3>
|
|
||||||
|
|
||||||
<p>you should reach out to the webmasters of
|
|
||||||
the websites that have duplicated your content and request them
|
|
||||||
to remove it or give you proper attribution (if available).</p>
|
|
||||||
|
|
||||||
<p>You can also use <a href="https://www.whois.com/whois/"
|
|
||||||
style="color: #D32F2F; text-decoration: none;">https://www.whois.com/whois/</a>
|
|
||||||
to get the contact details of the webmaster or domain owner.</p>
|
|
||||||
|
|
||||||
<p>If webmasters don't respond or cooperate, <strong>you can file a
|
|
||||||
DMCA complaint here:</strong> <a
|
|
||||||
href="https://support.google.com/legal/answer/3110420?hl=en"
|
|
||||||
style="color: #D32F2F; text-decoration: none;">https://support.google.com/legal/answer/3110420?hl=en</a>
|
|
||||||
<strong>with Google to request the removal of the duplicate
|
|
||||||
content from their search results.</strong></p>
|
|
||||||
|
|
||||||
<h3>Please refer to this for more information:</h3>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://support.google.com/legal/answer/3110420?hl=en&sjid=14235884554806745995-AP&authuser=2"
|
|
||||||
style="color: #D32F2F; text-decoration: none;">Report
|
|
||||||
Content for Legal Reasons</a></li>
|
|
||||||
<li><a href="https://www.dmca.com/FAQ/How-can-I-get-a-webpage-removed-from-Google-search-results"
|
|
||||||
style="color: #D32F2F; text-decoration: none;">How can I
|
|
||||||
get a webpage removed from Google search results?</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>Your safety is our main priority.</p>
|
|
||||||
|
|
||||||
<p>Thank you for choosing Litlyx every day as your analytics tool!
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Antonio,</p>
|
|
||||||
<p>CEO | Litlyx</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="padding:45px 0 0 0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<img src="https://react-email-demo-lpdmf0ryo-resend.vercel.app/static/yelp-footer.png"
|
|
||||||
style="display:block;outline:none;border:none;text-decoration:none;max-width:100%"
|
|
||||||
width="620" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p style="font-size:12px;line-height:24px;margin:16px 0;text-align:center;color:rgb(0,0,0, 0.7)">
|
|
||||||
2024 © Litlyx. All rights reserved.
|
|
||||||
<br>
|
|
||||||
Litlyx S.R.L. - Viale Tirreno, 187 - 00141 Rome - P.IVA: 17814721001- REA: RM-1743194
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
`
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
export const ANOMALY_VISITS_EVENTS_EMAIL = `<!DOCTYPE html
|
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html dir="ltr" lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
|
||||||
<meta name="x-apple-disable-message-reformatting" />
|
|
||||||
<!--$-->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body
|
|
||||||
style='background-color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif'>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="max-width:37.5em">
|
|
||||||
<tbody>
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="border:1px solid rgb(0,0,0, 0.1);border-radius:3px;overflow:hidden">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<img src="https://litlyx.com/images/locker2.png"
|
|
||||||
style="display:block;outline:none;border:none;text-decoration:none;max-width:100%"
|
|
||||||
width="620" />
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation" style="padding:20px;padding-bottom:0">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td data-id="__react-email-column">
|
|
||||||
<h1 style="font-size:32px;font-weight:bold;text-align:center">
|
|
||||||
Dear user
|
|
||||||
</h1>
|
|
||||||
<h2 style="font-size:26px;font-weight:bold;text-align:center">
|
|
||||||
Our AI Agent noticed a recent unexpected usage on your project
|
|
||||||
on Litlyx.
|
|
||||||
</h2>
|
|
||||||
<p
|
|
||||||
style="font-size:16px;line-height:24px;margin:16px 0;margin-top:-5px">
|
|
||||||
<b>Project: </b> [Project Name]
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
style="font-size:16px;line-height:24px;margin:16px 0;margin-top:-5px">
|
|
||||||
<b>Info: </b> [ENTRIES]
|
|
||||||
</p>
|
|
||||||
<p>If this spike in activity is expected, there’s no need to worry.
|
|
||||||
However, if you believe this could be unexpected or suspicious,
|
|
||||||
we recommend taking a closer look at your data on the
|
|
||||||
<strong>Litlyx Dashboard</strong>. You can analyze your recent
|
|
||||||
traffic and event logs to identify any irregularities or
|
|
||||||
potential issues.</p>
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation" style="padding:20px;padding-top:0">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td colspan="2" data-id="__react-email-column"
|
|
||||||
style="display:flex;justify-content:center;width:100%">
|
|
||||||
<a style="line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px;background-color:#5680f8;border-radius:3px;color:#FFF;font-weight:bold;border:1px solid rgb(0,0,0, 0.1);cursor:pointer;padding:12px 30px 12px 30px"
|
|
||||||
target="_blank"
|
|
||||||
href="https://dashboard.litlyx.com"><span></span><span
|
|
||||||
style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:9px">
|
|
||||||
Go to Dashboard</span><span></span></a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation" style="padding:20px;padding-bottom:0">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td data-id="__react-email-column">
|
|
||||||
|
|
||||||
<h3>What can I do?</h3>
|
|
||||||
|
|
||||||
<p>To better understand the situation, you can:</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>Review your traffic sources to see where the visits or
|
|
||||||
events are coming from.</li>
|
|
||||||
<li>Check for any unexpected patterns, such as a high number of
|
|
||||||
visits from unknown sources or abnormal event triggers.</li>
|
|
||||||
<li>Check your code to find bugs on a specific action that is
|
|
||||||
triggered in loops.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>If you need help understanding this activity or have any
|
|
||||||
concerns, feel free to reach out to our support team at <a
|
|
||||||
href="mailto:help@litlyx.com"
|
|
||||||
style="color: #D32F2F; text-decoration: none;"><strong>help@litlyx.com</strong></a>.
|
|
||||||
We are here to assist you!</p>
|
|
||||||
|
|
||||||
<p><strong>Your safety and data integrity are our top
|
|
||||||
priorities.</strong></p>
|
|
||||||
|
|
||||||
<p>Thank you for trusting Litlyx as your analytics tool!</p>
|
|
||||||
|
|
||||||
<p>Best regards,</p>
|
|
||||||
|
|
||||||
<p>Antonio,</p>
|
|
||||||
<p>CEO | Litlyx</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="padding:45px 0 0 0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<img src="https://react-email-demo-lpdmf0ryo-resend.vercel.app/static/yelp-footer.png"
|
|
||||||
style="display:block;outline:none;border:none;text-decoration:none;max-width:100%"
|
|
||||||
width="620" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p style="font-size:12px;line-height:24px;margin:16px 0;text-align:center;color:rgb(0,0,0, 0.7)">
|
|
||||||
2024 © Litlyx. All rights reserved.
|
|
||||||
<br>
|
|
||||||
Litlyx S.R.L. - Viale Tirreno, 187 - 00141 Rome - P.IVA: 17814721001- REA: RM-1743194
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
`
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
|
|
||||||
export const CONFIRM_EMAIL = `<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Email Confirmation</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
margin: 0;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
background-color: #ffffff;
|
|
||||||
padding: 20px;
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 0 auto;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
color: #333333;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
color: #555555;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 10px 20px;
|
|
||||||
background-color: #007bff;
|
|
||||||
color: #ffffff;
|
|
||||||
text-decoration: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
margin-top: 20px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #777777;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<h2>Confirm your email on Litlyx</h2>
|
|
||||||
<p>Hello,</p>
|
|
||||||
<p>Thank you so much for signing up on Litlyx! Please confirm your email address by clicking the button below:
|
|
||||||
</p>
|
|
||||||
<p><a href="[CONFIRM_LINK]" class="button">Confirm Email</a></p>
|
|
||||||
<p>If you didn't create an account with us, you can safely ignore this email.</p>
|
|
||||||
<p>We hope to hear from you soon!</p>
|
|
||||||
|
|
||||||
<div class="footer">
|
|
||||||
<p>© 2024 Litlyx. All rights reserved.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>`
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
export const LIMIT_50_EMAIL = `<!DOCTYPE html
|
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html dir="ltr" lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<link rel="preload" as="image" href="https://react-email-demo-lpdmf0ryo-resend.vercel.app/static/airbnb-logo.png" />
|
|
||||||
<link rel="preload" as="image"
|
|
||||||
href="https://react-email-demo-lpdmf0ryo-resend.vercel.app/static/airbnb-review-user.jpg" />
|
|
||||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
|
||||||
<meta name="x-apple-disable-message-reformatting" />
|
|
||||||
<!--$-->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body
|
|
||||||
style='background-color:#ffffff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif'>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="max-width:100%;margin:0 auto;padding:20px 0 48px;width:580px">
|
|
||||||
<tbody>
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<img alt="Founder" height="96"
|
|
||||||
src="https://litlyx.com/images/founder.jpg"
|
|
||||||
style="display:block;outline:none;border:none;text-decoration:none;margin:0 auto;margin-bottom:16px;border-radius:50%"
|
|
||||||
width="96" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="padding-bottom:20px">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<p
|
|
||||||
style="font-size:32px;line-height:1.3;margin:16px 0;font-weight:700;color:#484848">
|
|
||||||
You’ve Reached 50% of Your Litlyx Project Limit on [Project Name]
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
style="font-size:18px;line-height:1.4;margin:16px 0;color:#484848;padding:24px;background-color:#f2f3f3;border-radius:4px">
|
|
||||||
To avoid losing precious data, please remember to monitor your usage
|
|
||||||
on the <strong>Litlyx Dashboard</strong>. You can find your current
|
|
||||||
usage details under <strong>Settings > Billing Tab</strong>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>If you need more data collection storage, you may consider upgrading
|
|
||||||
your plan to get additional benefits and ensure uninterrupted data
|
|
||||||
collection.</p>
|
|
||||||
|
|
||||||
<p>Feel free to reply to this email or contact us at <a
|
|
||||||
href="mailto:help@litlyx.com"
|
|
||||||
style="color: #FF5733; text-decoration: none;">help@litlyx.com</a>
|
|
||||||
if you have any questions or need assistance.</p>
|
|
||||||
|
|
||||||
<p>Thank you for choosing Litlyx every day as your analytics tool.</p>
|
|
||||||
|
|
||||||
<p>Have a nice day!</p>
|
|
||||||
|
|
||||||
<p>Antonio,</p>
|
|
||||||
<p>CEO | Litlyx</p>
|
|
||||||
|
|
||||||
<a href="https://dashboard.litlyx.com/"
|
|
||||||
style="line-height:100%;text-decoration:none;display:block;max-width:100%;mso-padding-alt:0px;background-color:#5680f8;border-radius:3px;color:#fff;font-size:18px;padding-top:19px;padding-bottom:19px;text-align:center;width:100%;padding:19px 0px 19px 0px"
|
|
||||||
target="_blank"><span>
|
|
||||||
|
|
||||||
</span><span
|
|
||||||
style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:14.25px">Go to Dashboard</span><span></span></a>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<hr
|
|
||||||
style="width:100%;border:none;border-top:1px solid #eaeaea;border-color:#cccccc;margin:20px 0" />
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<p
|
|
||||||
style="font-size:14px;line-height:24px;margin:16px 0;color:#9ca299;margin-bottom:10px">
|
|
||||||
2024 © Litlyx. All rights reserved.
|
|
||||||
<br>
|
|
||||||
Litlyx S.R.L. - Viale Tirreno, 187 - 00141 Rome - P.IVA:
|
|
||||||
17814721001- REA: RM-1743194
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<!--/$-->
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
`
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
export const LIMIT_90_EMAIL = `<!DOCTYPE html
|
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html dir="ltr" lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<link rel="preload" as="image" href="https://react-email-demo-lpdmf0ryo-resend.vercel.app/static/airbnb-logo.png" />
|
|
||||||
<link rel="preload" as="image"
|
|
||||||
href="https://react-email-demo-lpdmf0ryo-resend.vercel.app/static/airbnb-review-user.jpg" />
|
|
||||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
|
||||||
<meta name="x-apple-disable-message-reformatting" />
|
|
||||||
<!--$-->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body
|
|
||||||
style='background-color:#ffffff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif'>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="max-width:100%;margin:0 auto;padding:20px 0 48px;width:580px">
|
|
||||||
<tbody>
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<img alt="Founder" height="96"
|
|
||||||
src="https://litlyx.com/images/founder.jpg"
|
|
||||||
style="display:block;outline:none;border:none;text-decoration:none;margin:0 auto;margin-bottom:16px;border-radius:50%"
|
|
||||||
width="96" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="padding-bottom:20px">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<p
|
|
||||||
style="font-size:32px;line-height:1.3;margin:16px 0;font-weight:700;color:#484848">
|
|
||||||
You’ve Reached 90% of Your Litlyx Project Limit on [Project Name]
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
style="font-size:18px;line-height:1.4;margin:16px 0;color:#484848;padding:24px;background-color:#f2f3f3;border-radius:4px">
|
|
||||||
To avoid losing precious data, please remember to monitor your usage
|
|
||||||
on the <strong>Litlyx Dashboard</strong>. You can find your current
|
|
||||||
usage details under <strong>Settings > Billing Tab</strong>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>If you need more data collection storage, you may consider upgrading
|
|
||||||
your plan to get additional benefits and ensure uninterrupted data
|
|
||||||
collection.</p>
|
|
||||||
|
|
||||||
<p>Feel free to reply to this email or contact us at <a
|
|
||||||
href="mailto:help@litlyx.com"
|
|
||||||
style="color: #FF5733; text-decoration: none;">help@litlyx.com</a>
|
|
||||||
if you have any questions or need assistance.</p>
|
|
||||||
|
|
||||||
<p>Thank you for choosing Litlyx every day as your analytics tool.</p>
|
|
||||||
|
|
||||||
<p>Have a nice day!</p>
|
|
||||||
|
|
||||||
<p>Antonio,</p>
|
|
||||||
<p>CEO | Litlyx</p>
|
|
||||||
|
|
||||||
<a href="https://dashboard.litlyx.com/"
|
|
||||||
style="line-height:100%;text-decoration:none;display:block;max-width:100%;mso-padding-alt:0px;background-color:#5680f8;border-radius:3px;color:#fff;font-size:18px;padding-top:19px;padding-bottom:19px;text-align:center;width:100%;padding:19px 0px 19px 0px"
|
|
||||||
target="_blank"><span>
|
|
||||||
|
|
||||||
</span><span
|
|
||||||
style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:14.25px">Go to Dashboard</span><span></span></a>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<hr
|
|
||||||
style="width:100%;border:none;border-top:1px solid #eaeaea;border-color:#cccccc;margin:20px 0" />
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<p
|
|
||||||
style="font-size:14px;line-height:24px;margin:16px 0;color:#9ca299;margin-bottom:10px">
|
|
||||||
2024 © Litlyx. All rights reserved.
|
|
||||||
<br>
|
|
||||||
Litlyx S.R.L. - Viale Tirreno, 187 - 00141 Rome - P.IVA:
|
|
||||||
17814721001- REA: RM-1743194
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<!--/$-->
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
||||||
`
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
export const LIMIT_MAX_EMAIL = `<!DOCTYPE html
|
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html dir="ltr" lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<link rel="preload" as="image" href="https://react-email-demo-lpdmf0ryo-resend.vercel.app/static/airbnb-logo.png" />
|
|
||||||
<link rel="preload" as="image"
|
|
||||||
href="https://react-email-demo-lpdmf0ryo-resend.vercel.app/static/airbnb-review-user.jpg" />
|
|
||||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
|
||||||
<meta name="x-apple-disable-message-reformatting" />
|
|
||||||
<!--$-->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body
|
|
||||||
style='background-color:#ffffff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif'>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="max-width:100%;margin:0 auto;padding:20px 0 48px;width:580px">
|
|
||||||
<tbody>
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<img alt="Founder" height="96"
|
|
||||||
src="https://litlyx.com/images/founder.jpg"
|
|
||||||
style="display:block;outline:none;border:none;text-decoration:none;margin:0 auto;margin-bottom:16px;border-radius:50%"
|
|
||||||
width="96" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="padding-bottom:20px">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<p
|
|
||||||
style="font-size:32px;line-height:1.3;margin:16px 0;font-weight:700;color:#484848">
|
|
||||||
You’ve Reached Your Litlyx Project Limit on [Project Name]
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
style="font-size:18px;line-height:1.4;margin:16px 0;color:#484848;padding:24px;background-color:#ffbb03;border-radius:4px">
|
|
||||||
We noticed that Litlyx has stopped collecting data for your project.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
To help you avoid losing valuable insights, we recommend keeping an
|
|
||||||
eye on your usage via the Litlyx Dashboard.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
You can view your current usage details under Settings > Billing
|
|
||||||
Tab.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
If you need additional storage for data collection, consider
|
|
||||||
upgrading your plan to unlock more benefits and ensure uninterrupted
|
|
||||||
service.
|
|
||||||
</p>
|
|
||||||
<p style="font-weight: 700;">
|
|
||||||
As a token of appreciation, we're offering you 25% off for life at
|
|
||||||
checkout with the code LIT25.
|
|
||||||
</p>
|
|
||||||
Thank you for choosing Litlyx as your trusted analytics tool.
|
|
||||||
<p></p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
If you have any questions or need assistance, feel free to reply to
|
|
||||||
this email or contact us at <a href="mailto:help@litlyx.com"
|
|
||||||
style="color: #FF5733; text-decoration: none;">help@litlyx.com</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Have a great day!
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Antonio
|
|
||||||
CEO | Litlyx
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
|
||||||
<a href="https://dashboard.litlyx.com/"
|
|
||||||
style="line-height:100%;text-decoration:none;display:block;max-width:100%;mso-padding-alt:0px;background-color:#5680f8;border-radius:3px;color:#fff;font-size:18px;padding-top:19px;padding-bottom:19px;text-align:center;width:100%;padding:19px 0px 19px 0px"
|
|
||||||
target="_blank"><span>
|
|
||||||
|
|
||||||
</span><span
|
|
||||||
style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:14.25px">Go
|
|
||||||
to Dashboard</span><span></span></a>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<hr
|
|
||||||
style="width:100%;border:none;border-top:1px solid #eaeaea;border-color:#cccccc;margin:20px 0" />
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<p
|
|
||||||
style="font-size:14px;line-height:24px;margin:16px 0;color:#9ca299;margin-bottom:10px">
|
|
||||||
2024 © Litlyx. All rights reserved.
|
|
||||||
<br>
|
|
||||||
Litlyx S.R.L. - Viale Tirreno, 187 - 00141 Rome - P.IVA:
|
|
||||||
17814721001- REA: RM-1743194
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<!--/$-->
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
||||||
`
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
|
|
||||||
export const PURCHASE_EMAIL = `<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Thank You for Upgrading Your Litlyx Plan!</title>
|
|
||||||
</head>
|
|
||||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333;">
|
|
||||||
|
|
||||||
<!-- Email Content -->
|
|
||||||
|
|
||||||
<p>Dear User,</p>
|
|
||||||
|
|
||||||
<p>We are thrilled to inform you that <strong>[Project Name]</strong> on <strong>Litlyx</strong> has successfully been upgraded to a higher plan! Thank you for choosing to elevate your experience with us and for believing in our project.</p>
|
|
||||||
|
|
||||||
<p>We appreciate your trust in Litlyx and are committed to providing you with the best analytics experience. Your support helps us to continually improve our platform and bring new features to make your analytics journey even better.</p>
|
|
||||||
|
|
||||||
<p>You can find your current plan details and download your invoices under <strong>Settings > Billing Tab</strong>.</p>
|
|
||||||
|
|
||||||
<h3>What does this mean for you?</h3>
|
|
||||||
|
|
||||||
<p>With your upgraded plan, you can now enjoy more data collection, advanced features, and additional benefits to enhance your data analysis capabilities:</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>Access to more storage and increased data limits.</li>
|
|
||||||
<li>Advanced analytics tools like IP-Company Matching, download CSV for your raw data, AI insights, and more.</li>
|
|
||||||
<li>Priority support to help you make the most of your Litlyx experience on Slack or Discord!</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>If you have any questions about your new plan or need assistance, feel free to reach out to our support team at <a href="mailto:help@litlyx.com" style="color: #28a745; text-decoration: none;"><strong>help@litlyx.com</strong></a>. We’re here to help you make the most out of your upgraded plan!</p>
|
|
||||||
|
|
||||||
<p><strong>Thank you for using Litlyx every day as your analytics tool and for being a part of our journey.</strong></p>
|
|
||||||
|
|
||||||
<p>We look forward to continuing to support your growth and success!</p>
|
|
||||||
|
|
||||||
<p>Best regards,</p>
|
|
||||||
|
|
||||||
<p>Antonio,</p>
|
|
||||||
<p>CEO | Litlyx</p>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
export const RESET_PASSWORD_EMAIL = `<!DOCTYPE html
|
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html dir="ltr" lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
|
||||||
<meta name="x-apple-disable-message-reformatting" />
|
|
||||||
<!--$-->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body
|
|
||||||
style='background-color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif'>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="max-width:37.5em">
|
|
||||||
<tbody>
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="border:1px solid rgb(0,0,0, 0.1);border-radius:3px;overflow:hidden">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<img src="https://litlyx.com/images/locker2.png"
|
|
||||||
style="display:block;outline:none;border:none;text-decoration:none;max-width:100%"
|
|
||||||
width="620" />
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation" style="padding:20px;padding-bottom:0">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td data-id="__react-email-column">
|
|
||||||
<h1 style="font-size:32px;font-weight:bold;text-align:center">
|
|
||||||
Dear user
|
|
||||||
</h1>
|
|
||||||
<h2 style="font-size:26px;font-weight:bold;text-align:center">
|
|
||||||
Below is the temporary password for logging in again to the
|
|
||||||
Litlyx dashboard.
|
|
||||||
</h2>
|
|
||||||
<p style="font-size:16px;line-height:24px;margin:16px 0">
|
|
||||||
<b>Temporary Password: </b> [NEW_PASSWORD]
|
|
||||||
<!-- September 7, 2022 at 10:58 AM -->
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p style="font-size:16px;line-height:24px;margin:16px 0">
|
|
||||||
Please ensure that you change your password as soon as possible.
|
|
||||||
To do so, go to <b>Settings > Account</b> in the dashboard. <br>
|
|
||||||
If you need further assistance, feel free to contact us at
|
|
||||||
<a href="mailto:help@litlyx.com">help@litlyx.com</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0"
|
|
||||||
role="presentation" style="padding:20px;padding-top:0">
|
|
||||||
<tbody style="width:100%">
|
|
||||||
<tr style="width:100%">
|
|
||||||
<td colspan="2" data-id="__react-email-column"
|
|
||||||
style="display:flex;justify-content:center;width:100%">
|
|
||||||
<a style="line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px;background-color:#5680f8;border-radius:3px;color:#FFF;font-weight:bold;border:1px solid rgb(0,0,0, 0.1);cursor:pointer;padding:12px 30px 12px 30px"
|
|
||||||
target="_blank"
|
|
||||||
href="https://dashboard.litlyx.com"><span></span><span
|
|
||||||
style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:9px">
|
|
||||||
Go to Dashboard</span><span></span></a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
||||||
style="padding:45px 0 0 0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<img src="https://react-email-demo-lpdmf0ryo-resend.vercel.app/static/yelp-footer.png"
|
|
||||||
style="display:block;outline:none;border:none;text-decoration:none;max-width:100%"
|
|
||||||
width="620" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p style="font-size:12px;line-height:24px;margin:16px 0;text-align:center;color:rgb(0,0,0, 0.7)">
|
|
||||||
2024 © Litlyx. All rights reserved.
|
|
||||||
<br>
|
|
||||||
Litlyx S.R.L. - Viale Tirreno, 187 - 00141 Rome - P.IVA: 17814721001- REA: RM-1743194
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
||||||
`
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
export const WELCOME_EMAIL = `
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Welcome to Litlyx!</title>
|
|
||||||
</head>
|
|
||||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333;">
|
|
||||||
|
|
||||||
<p>We’re happy to have you onboard,</p>
|
|
||||||
|
|
||||||
<p>At Litlyx, we’re committed to creating the best analytics collection experience for everybody, starting from developers.</p>
|
|
||||||
|
|
||||||
<p>Here are a few things you can do to get started tracking analytics today:</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li><strong><a href="https://dashboard.litlyx.com" style="color: #007BFF; text-decoration: none;">Create a new project</a></strong> – by just naming it</li>
|
|
||||||
<li><strong><a style="color: #0a0a0a; text-decoration: none;">Copy the universal Script</a></strong> – we provide you the snippets to copy in your index.html file and start instantly to track metrics on your website or web app.</li>
|
|
||||||
<li><strong><a style="color: #0a0a0a; text-decoration: none;">Deploy</a></strong> – Litlyx is production ready.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>If you have any questions or need support, visit <a href="http://docs.litlyx.com" style="color: #007BFF;">docs.litlyx.com</a>.</p>
|
|
||||||
|
|
||||||
<p>Feel free to reply to this email or reach out to our team at <a href="mailto:help@litlyx.com" style="color: #007BFF;">help@litlyx.com</a>. We’re here to help!</p>
|
|
||||||
|
|
||||||
<p>Link to Discord for developer support: <a href="https://discord.com/invite/9cQykjsmWX" style="color: #007BFF;">https://discord.com/invite/9cQykjsmWX</a></p>
|
|
||||||
|
|
||||||
<p>Thank you for joining us, and we look forward to seeing you around.</p>
|
|
||||||
|
|
||||||
<p>We want to make analytics the freshest thing on the web.</p>
|
|
||||||
|
|
||||||
<p>Antonio,</p>
|
|
||||||
<p>CEO | Litlyx</p>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`
|
|
||||||
Reference in New Issue
Block a user