Skip to content

Commit a927657

Browse files
authored
Merge pull request #21 from MicroPyramid/dev
Dev
2 parents afcd8fb + 6c31afe commit a927657

File tree

54 files changed

+17740
-2690
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+17740
-2690
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-- CreateTable
2+
CREATE TABLE "NewsletterSubscriber" (
3+
"id" TEXT NOT NULL,
4+
"email" TEXT NOT NULL,
5+
"isActive" BOOLEAN NOT NULL DEFAULT true,
6+
"subscribedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
7+
"unsubscribedAt" TIMESTAMP(3),
8+
"confirmationToken" TEXT,
9+
"isConfirmed" BOOLEAN NOT NULL DEFAULT false,
10+
"confirmedAt" TIMESTAMP(3),
11+
"ipAddress" TEXT,
12+
"userAgent" TEXT,
13+
14+
CONSTRAINT "NewsletterSubscriber_pkey" PRIMARY KEY ("id")
15+
);
16+
17+
-- CreateIndex
18+
CREATE UNIQUE INDEX "NewsletterSubscriber_email_key" ON "NewsletterSubscriber"("email");
19+
20+
-- CreateIndex
21+
CREATE UNIQUE INDEX "NewsletterSubscriber_confirmationToken_key" ON "NewsletterSubscriber"("confirmationToken");
22+
23+
-- CreateIndex
24+
CREATE INDEX "NewsletterSubscriber_email_idx" ON "NewsletterSubscriber"("email");
25+
26+
-- CreateIndex
27+
CREATE INDEX "NewsletterSubscriber_isActive_idx" ON "NewsletterSubscriber"("isActive");
28+
29+
-- CreateIndex
30+
CREATE INDEX "NewsletterSubscriber_subscribedAt_idx" ON "NewsletterSubscriber"("subscribedAt");

prisma/schema.prisma

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ model Contact {
164164
leads Lead[] // Keep this relation for historical tracking only
165165
comments Comment[]
166166
quotes Quote[] @relation("ContactQuotes")
167-
relatedAccounts AccountContactRelationship[]
167+
relatedAccounts AccountContactRelationship[]
168168
}
169169

170170
enum LeadSource {
@@ -645,3 +645,20 @@ enum ContentBlockType {
645645
CODE
646646
IMAGE
647647
}
648+
649+
model NewsletterSubscriber {
650+
id String @id @default(uuid())
651+
email String @unique
652+
isActive Boolean @default(true)
653+
subscribedAt DateTime @default(now())
654+
unsubscribedAt DateTime?
655+
confirmationToken String? @unique
656+
isConfirmed Boolean @default(false)
657+
confirmedAt DateTime?
658+
ipAddress String?
659+
userAgent String?
660+
661+
@@index([email])
662+
@@index([isActive])
663+
@@index([subscribedAt])
664+
}

src/lib/newsletter.js

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Newsletter utility functions for email confirmation and management
2+
3+
/**
4+
* Generate unsubscribe link for newsletter
5+
* @param {string} token - Confirmation token
6+
* @param {string} baseUrl - Base URL of the application
7+
* @returns {string} Unsubscribe URL
8+
*/
9+
export function generateUnsubscribeLink(token, baseUrl = 'https://bottlecrm.com') {
10+
return `${baseUrl}/unsubscribe?token=${token}`;
11+
}
12+
13+
/**
14+
* Validate email format
15+
* @param {string} email - Email to validate
16+
* @returns {boolean} True if email is valid
17+
*/
18+
export function isValidEmail(email) {
19+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
20+
return emailRegex.test(email);
21+
}
22+
23+
/**
24+
* Generate email confirmation template
25+
* @param {string} email - Subscriber email
26+
* @param {string} unsubscribeLink - Unsubscribe link
27+
* @returns {object} Email template with subject and body
28+
*/
29+
export function generateWelcomeEmail(email, unsubscribeLink) {
30+
return {
31+
subject: 'Welcome to BottleCRM Newsletter!',
32+
html: `
33+
<!DOCTYPE html>
34+
<html>
35+
<head>
36+
<meta charset="utf-8">
37+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
38+
<title>Welcome to BottleCRM Newsletter</title>
39+
</head>
40+
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
41+
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 30px; border-radius: 10px; text-align: center; margin-bottom: 30px;">
42+
<h1 style="color: white; margin: 0; font-size: 28px;">Welcome to BottleCRM!</h1>
43+
<p style="color: #f0f0f0; margin: 10px 0 0 0; font-size: 16px;">Thank you for subscribing to our newsletter</p>
44+
</div>
45+
46+
<div style="background: #f8f9fa; padding: 30px; border-radius: 10px; margin-bottom: 30px;">
47+
<h2 style="color: #333; margin-top: 0;">What to expect:</h2>
48+
<ul style="padding-left: 20px;">
49+
<li style="margin-bottom: 10px;">🚀 <strong>Product Updates:</strong> Be the first to know about new features and improvements</li>
50+
<li style="margin-bottom: 10px;">💡 <strong>CRM Tips:</strong> Best practices to maximize your customer relationship management</li>
51+
<li style="margin-bottom: 10px;">📊 <strong>Industry Insights:</strong> Stay ahead with the latest CRM trends and strategies</li>
52+
<li style="margin-bottom: 10px;">🎯 <strong>Exclusive Content:</strong> Guides and resources available only to subscribers</li>
53+
</ul>
54+
</div>
55+
56+
<div style="text-align: center; margin-bottom: 30px;">
57+
<a href="https://bottlecrm.com/demo" style="background: #667eea; color: white; padding: 15px 30px; text-decoration: none; border-radius: 5px; display: inline-block; font-weight: bold;">Try BottleCRM Free</a>
58+
</div>
59+
60+
<div style="text-align: center; color: #666; font-size: 14px; border-top: 1px solid #ddd; padding-top: 20px;">
61+
<p>You're receiving this email because you subscribed to BottleCRM newsletter.</p>
62+
<p>
63+
<a href="${unsubscribeLink}" style="color: #666; text-decoration: underline;">Unsubscribe</a> |
64+
<a href="https://bottlecrm.com" style="color: #666; text-decoration: underline;">Visit Website</a>
65+
</p>
66+
<p style="margin-top: 20px;">
67+
<strong>BottleCRM</strong> by MicroPyramid<br>
68+
The free, open-source CRM for startups
69+
</p>
70+
</div>
71+
</body>
72+
</html>
73+
`,
74+
text: `
75+
Welcome to BottleCRM Newsletter!
76+
77+
Thank you for subscribing to our newsletter. Here's what you can expect:
78+
79+
• Product Updates: Be the first to know about new features and improvements
80+
• CRM Tips: Best practices to maximize your customer relationship management
81+
• Industry Insights: Stay ahead with the latest CRM trends and strategies
82+
• Exclusive Content: Guides and resources available only to subscribers
83+
84+
Try BottleCRM Free: https://bottlecrm.com/demo
85+
86+
You're receiving this email because you subscribed to BottleCRM newsletter.
87+
To unsubscribe, visit: ${unsubscribeLink}
88+
89+
BottleCRM by MicroPyramid
90+
The free, open-source CRM for startups
91+
https://bottlecrm.com
92+
`
93+
};
94+
}
95+
96+
/**
97+
* Generate newsletter template for regular updates
98+
* @param {object} content - Newsletter content
99+
* @param {string} unsubscribeLink - Unsubscribe link
100+
* @returns {object} Newsletter template with subject and body
101+
*/
102+
export function generateNewsletterTemplate(content, unsubscribeLink) {
103+
const { subject, headline, articles = [], ctaText = 'Learn More', ctaLink = 'https://bottlecrm.com' } = content;
104+
105+
const articlesHtml = articles.map(article => `
106+
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #667eea;">
107+
<h3 style="margin: 0 0 10px 0; color: #333;">${article.title}</h3>
108+
<p style="margin: 0 0 15px 0; color: #666; line-height: 1.6;">${article.excerpt}</p>
109+
<a href="${article.link}" style="color: #667eea; text-decoration: none; font-weight: 500;">Read more →</a>
110+
</div>
111+
`).join('');
112+
113+
return {
114+
subject,
115+
html: `
116+
<!DOCTYPE html>
117+
<html>
118+
<head>
119+
<meta charset="utf-8">
120+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
121+
<title>${subject}</title>
122+
</head>
123+
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f5f5f5;">
124+
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 30px; border-radius: 10px; text-align: center; margin-bottom: 30px;">
125+
<h1 style="color: white; margin: 0; font-size: 24px;">${headline}</h1>
126+
</div>
127+
128+
<div style="margin-bottom: 30px;">
129+
${articlesHtml}
130+
</div>
131+
132+
<div style="text-align: center; margin-bottom: 30px;">
133+
<a href="${ctaLink}" style="background: #667eea; color: white; padding: 15px 30px; text-decoration: none; border-radius: 5px; display: inline-block; font-weight: bold;">${ctaText}</a>
134+
</div>
135+
136+
<div style="text-align: center; color: #666; font-size: 14px; border-top: 1px solid #ddd; padding-top: 20px;">
137+
<p>You're receiving this email because you subscribed to BottleCRM newsletter.</p>
138+
<p>
139+
<a href="${unsubscribeLink}" style="color: #666; text-decoration: underline;">Unsubscribe</a> |
140+
<a href="https://bottlecrm.com" style="color: #666; text-decoration: underline;">Visit Website</a>
141+
</p>
142+
<p style="margin-top: 20px;">
143+
<strong>BottleCRM</strong> by MicroPyramid<br>
144+
The free, open-source CRM for startups
145+
</p>
146+
</div>
147+
</body>
148+
</html>
149+
`
150+
};
151+
}

src/routes/(admin)/admin/+layout.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@
3131
<FileText class="w-4 h-4 mr-2" />
3232
Blog Posts
3333
</a>
34-
<a href="/admin/analytics" class="flex items-center px-3 py-2 text-sm font-medium text-gray-700 rounded-md hover:bg-gray-100 hover:text-blue-600 transition-colors">
34+
<a href="/admin/newsletter" class="flex items-center px-3 py-2 text-sm font-medium text-gray-700 rounded-md hover:bg-gray-100 hover:text-blue-600 transition-colors">
3535
<ChartBar class="w-4 h-4 mr-2" />
36-
Analytics
36+
Newsletter
3737
</a>
3838
</nav>
3939
</div>

0 commit comments

Comments
 (0)