Skip to content

Commit 88a8712

Browse files
authored
Merge pull request #67 from MicroPyramid/dev
Dev
2 parents 4c99b82 + 590fe1c commit 88a8712

Some content is hidden

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

47 files changed

+1272
-568
lines changed

src/hooks.server.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { redirect } from '@sveltejs/kit';
55
export async function handle({ event, resolve }) {
66
const sessionId = await event.cookies.get('session');
77
// console.log(sessionId, '-----------------sessionid')
8-
let user = false
8+
let user = null;
99
if(sessionId && sessionId!=''){
1010
user = await prisma.user.findFirst({
1111
where: {

src/lib/newsletter.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Newsletter utility functions for email confirmation and management
22

33
/**
4-
* Generate unsubscribe link for newsletter
4+
* Generate unsubscribe link
55
* @param {string} token - Confirmation token
66
* @param {string} baseUrl - Base URL of the application
77
* @returns {string} Unsubscribe URL
@@ -95,14 +95,14 @@ export function generateWelcomeEmail(email, unsubscribeLink) {
9595

9696
/**
9797
* Generate newsletter template for regular updates
98-
* @param {object} content - Newsletter content
98+
* @param {any} content - Newsletter content
9999
* @param {string} unsubscribeLink - Unsubscribe link
100100
* @returns {object} Newsletter template with subject and body
101101
*/
102102
export function generateNewsletterTemplate(content, unsubscribeLink) {
103103
const { subject, headline, articles = [], ctaText = 'Learn More', ctaLink = 'https://bottlecrm.io' } = content;
104104

105-
const articlesHtml = articles.map(article => `
105+
const articlesHtml = articles.map(/** @param {any} article */ article => `
106106
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #667eea;">
107107
<h3 style="margin: 0 0 10px 0; color: #333;">${article.title}</h3>
108108
<p style="margin: 0 0 15px 0; color: #666; line-height: 1.6;">${article.excerpt}</p>

src/lib/stores/auth.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ export const auth = writable({
77
});
88

99
// Helper to get the current session user from event.locals (SvelteKit convention)
10+
/**
11+
* @param {any} event
12+
*/
1013
export function getSessionUser(event) {
1114
// If you use event.locals.user for authentication, return it
1215
// You can adjust this logic if your user is stored differently

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
import '../../app.css'
33
import { Menu, Bell, User, Search, FileText, Settings, ChartBar, Home, X, LogOut } from '@lucide/svelte';
44
5-
/** @type {{ data: import('./admin/$types').LayoutData, children: import('svelte').Snippet }} */
5+
/** @type {{ data?: any, children: import('svelte').Snippet }} */
66
let { data, children } = $props();
77
88
let mobileMenuOpen = $state(false);
99
10+
const handleLogout = () => {
11+
// Perform logout action - you might want to redirect to logout endpoint
12+
window.location.href = '/logout';
13+
};
14+
1015
</script>
1116

1217
<div class="min-h-screen bg-gray-50">

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
const { metrics } = data;
1818
1919
// Format numbers with commas
20-
const formatNumber = (num) => {
20+
const formatNumber = (/** @type {any} */ num) => {
2121
return new Intl.NumberFormat('en-US').format(num);
2222
};
2323
</script>

src/routes/(admin)/admin/blogs/+page.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
{#each data.blogs as blog}
2525
<tr class="hover:bg-gray-50">
2626
<td class="py-2 px-4 border-b"><a href="/admin/blogs/{blog.id}/">{blog.title}</a> - <a href="/admin/blogs/{blog.id}/edit/">Edit</a></td>
27-
<td class="py-2 px-4 border-b">{blog.category}</td>
27+
<td class="py-2 px-4 border-b">N/A</td>
2828
<td class="py-2 px-4 border-b">
2929
{#if blog.draft}
3030
<span class="inline-block px-2 py-1 text-xs font-semibold text-yellow-800 bg-yellow-100 rounded">Draft</span>

src/routes/(admin)/admin/blogs/[id]/+page.svelte

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
1818
<div class="flex justify-between items-center">
1919
<nav class="text-sm text-gray-500 dark:text-gray-400">
20-
<span>Admin</span> <span class="mx-2">/</span> <span>Blogs</span> <span class="mx-2">/</span> <span class="text-gray-900 dark:text-white">{data.blog.title}</span>
20+
<span>Admin</span> <span class="mx-2">/</span> <span>Blogs</span> <span class="mx-2">/</span> <span class="text-gray-900 dark:text-white">{data.blog?.title || 'Blog'}</span>
2121
</nav>
2222
<a
23-
href={`/admin/blogs/${data.blog.id}/edit`}
23+
href={`/admin/blogs/${data.blog?.id}/edit`}
2424
class="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-medium text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900"
2525
>
2626
<Edit size={16} />
@@ -35,15 +35,12 @@
3535
<!-- Blog Header -->
3636
<header class="text-center mb-12">
3737
<div class="mb-4">
38-
<a
39-
href="/blog/category/{data.blog.categorySlug}"
40-
class="inline-block px-3 py-1 rounded-full bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200 font-medium text-sm hover:bg-yellow-200 dark:hover:bg-yellow-800 transition-colors"
41-
>
42-
{data.blog.category}
43-
</a>
38+
<span class="inline-block px-3 py-1 rounded-full bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200 font-medium text-sm">
39+
Blog Post
40+
</span>
4441
</div>
4542
<h1 class="text-3xl md:text-4xl lg:text-5xl font-bold text-gray-900 dark:text-white mb-6 leading-tight">
46-
{data.blog.title}
43+
{data.blog?.title || 'Untitled'}
4744
</h1>
4845
</header>
4946

@@ -52,7 +49,7 @@
5249
<!-- Main Content Column -->
5350
<article class="lg:col-span-8 xl:col-span-9">
5451
<div class="prose prose-lg dark:prose-invert max-w-none">
55-
{#each data.blog.contentBlocks as block}
52+
{#each data.blog?.contentBlocks || [] as block}
5653
<div class="mb-8">
5754
{#if block.type == "MARKDOWN"}
5855
<div class="text-gray-800 dark:text-gray-200 leading-relaxed">
@@ -118,8 +115,8 @@
118115
<h3 class="font-semibold text-gray-900 dark:text-white mb-4">Blog Details</h3>
119116
<div class="space-y-3 text-sm">
120117
<div>
121-
<span class="text-gray-600 dark:text-gray-400">Category:</span>
122-
<span class="ml-2 text-gray-900 dark:text-white">{data.blog.category}</span>
118+
<span class="text-gray-600 dark:text-gray-400">Type:</span>
119+
<span class="ml-2 text-gray-900 dark:text-white">Blog Post</span>
123120
</div>
124121
<div>
125122
<span class="text-gray-600 dark:text-gray-400">Status:</span>
@@ -134,14 +131,14 @@
134131
</div>
135132

136133
<MetaTags
137-
title={data.blog.seoTitle}
134+
title={data.blog?.seoTitle || 'Blog Post'}
138135
titleTemplate="%s | BottleCRM"
139-
description={data.blog.seoDescription}
140-
canonical={"https://bottlecrm.com/blog/" + data.blog.slug + "/"}
136+
description={data.blog?.seoDescription || 'Blog post'}
137+
canonical={"https://bottlecrm.com/blog/" + (data.blog?.slug || '') + "/"}
141138
openGraph={{
142-
url: data.blog.slug,
143-
title: data.blog.seoTitle,
144-
description: data.blog.seoDescription,
139+
url: data.blog?.slug || '',
140+
title: data.blog?.seoTitle || 'Blog Post',
141+
description: data.blog?.seoDescription || 'Blog post',
145142
images: [
146143
{
147144
url: "https://bottlecrm.com/images/logo.png",
@@ -150,14 +147,13 @@
150147
alt: "BottleCRM - Open Source CRM Solution",
151148
},
152149
],
153-
site_name: "BottleCRM",
150+
siteName: "BottleCRM",
154151
}}
155152
twitter={{
156-
handle: "@bottlecrm",
157153
site: "@bottlecrm",
158154
cardType: "summary_large_image",
159-
title: data.blog.seoTitle,
160-
description: data.blog.seoDescription,
155+
title: data.blog?.seoTitle || 'Blog Post',
156+
description: data.blog?.seoDescription || 'Blog post',
161157
image: "https://bottlecrm.com/images/logo.png",
162158
imageAlt: "BottleCRM - Open Source CRM Solution",
163159
}}

src/routes/(admin)/admin/blogs/[id]/edit/+page.server.js

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,44 +21,66 @@ export const actions = {
2121

2222
'add-block': async ({ request, params }) => {
2323
const form = await request.formData();
24+
const type = form.get('type')?.toString();
25+
const content = form.get('content')?.toString();
26+
const displayOrder = form.get('displayOrder')?.toString();
27+
28+
if (!type || !content || !displayOrder) {
29+
return { success: false, error: 'Missing required fields' };
30+
}
31+
2432
await prisma.blogContentBlock.create({
2533
data: {
2634
blogId: params.id,
27-
type: form.get('type'),
28-
content: form.get('content'),
29-
displayOrder: Number(form.get('displayOrder')),
35+
type: /** @type {import('@prisma/client').ContentBlockType} */ (type),
36+
content: content,
37+
displayOrder: Number(displayOrder),
3038
draft: form.get('draft') === 'on'
3139
}
3240
});
3341
return { success: true };
3442
},
3543
'edit-block': async ({ request }) => {
3644
const form = await request.formData();
45+
const id = form.get('id')?.toString();
46+
const type = form.get('type')?.toString();
47+
const content = form.get('content')?.toString();
48+
49+
if (!id || !type || !content) {
50+
return { success: false, error: 'Missing required fields' };
51+
}
52+
3753
await prisma.blogContentBlock.update({
38-
where: { id: form.get('id') },
54+
where: { id: id },
3955
data: {
40-
type: form.get('type'),
41-
content: form.get('content'),
56+
type: /** @type {import('@prisma/client').ContentBlockType} */ (type),
57+
content: content,
4258
draft: form.get('draft') === 'on'
4359
}
4460
});
4561
return { success: true };
4662
},
4763
'delete-block': async ({ request }) => {
4864
const form = await request.formData();
65+
const id = form.get('id')?.toString();
66+
67+
if (!id) {
68+
return { success: false, error: 'Missing block ID' };
69+
}
70+
4971
await prisma.blogContentBlock.delete({
50-
where: { id: form.get('id') }
72+
where: { id: id }
5173
});
5274
return { success: true };
5375
},
5476
'update-blog': async ({ request, params }) => {
5577
const form = await request.formData();
5678
const data = {
57-
title: form.get('title'),
58-
seoTitle: form.get('seoTitle'),
59-
seoDescription: form.get('seoDescription'),
60-
excerpt: form.get('excerpt'),
61-
slug: form.get('slug'),
79+
title: form.get('title')?.toString() || '',
80+
seoTitle: form.get('seoTitle')?.toString() || '',
81+
seoDescription: form.get('seoDescription')?.toString() || '',
82+
excerpt: form.get('excerpt')?.toString() || '',
83+
slug: form.get('slug')?.toString() || '',
6284
draft: form.get('draft') === 'on'
6385
};
6486
await prisma.blogPost.update({
@@ -70,7 +92,13 @@ export const actions = {
7092
,
7193
'reorder-blocks': async ({ request, params }) => {
7294
const form = await request.formData();
73-
const order = JSON.parse(form.get('order'));
95+
const orderStr = form.get('order')?.toString();
96+
97+
if (!orderStr) {
98+
return { success: false, error: 'Missing order data' };
99+
}
100+
101+
const order = JSON.parse(orderStr);
74102
for (const { id, displayOrder } of order) {
75103
await prisma.blogContentBlock.update({
76104
where: { id },

src/routes/(admin)/admin/blogs/[id]/edit/+page.svelte

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@
22
import { dndzone } from "svelte-dnd-action";
33
/** @type {{ data: import('./$types').PageData }} */
44
export let data;
5-
export let form;
65
/** @type {any} */
7-
let blog = data.blog;
6+
let blog = /** @type {any} */ (data)?.blog || {};
87
/** @type {any[]} */
9-
let contentBlocks = blog.contentBlocks
8+
let contentBlocks = blog?.contentBlocks || []
109
1110
// Drag and drop handler for reordering content blocks
12-
async function handleReorder({ detail }) {
11+
async function handleReorder(/** @type {any} */ { detail }) {
1312
// detail.items is the new order of contentBlocks
1413
// Reorder contentBlocks array to match the new order from dndzone
15-
contentBlocks = detail.items.map((item, idx) => ({
14+
contentBlocks = detail.items.map((/** @type {any} */ item, /** @type {any} */ idx) => ({
1615
...item,
1716
displayOrder: idx + 1
1817
}));
@@ -29,6 +28,7 @@
2928
let message = "";
3029
3130
// For editing/adding content blocks
31+
/** @type {any} */
3232
let editingBlockId = null;
3333
let newBlock = {
3434
type: "MARKDOWN",
@@ -37,14 +37,14 @@
3737
draft: false,
3838
};
3939
40-
function startEditBlock(block) {
40+
function startEditBlock(/** @type {any} */ block) {
4141
editingBlockId = block.id;
4242
/** @type {any} */ (block)._editContent = block.content;
4343
/** @type {any} */ (block)._editType = block.type;
4444
/** @type {any} */ (block)._editDraft = block.draft;
4545
}
4646
47-
function cancelEditBlock(block) {
47+
function cancelEditBlock(/** @type {any} */ block) {
4848
editingBlockId = null;
4949
delete block._editContent;
5050
delete block._editType;
@@ -61,12 +61,13 @@
6161
.replace(/\s+/g, '-')
6262
.replace(/[^\w-]+/g, '');
6363
}
64-
let editable_title = form?.data?.title ?? blog.title;
65-
let slug = form?.data?.slug ?? blog.slug;
64+
let editable_title = blog?.title || '';
65+
let slug = blog?.slug || '';
6666
6767
6868
// Initialize previous_editable_title_for_slug_generation to undefined
6969
// so we can detect the first run of the reactive block.
70+
/** @type {any} */
7071
let previous_editable_title_for_slug_generation = undefined;
7172
7273
$: {

src/routes/(admin)/admin/blogs/new/+page.server.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,27 @@ export async function load() {
1010
export const actions = {
1111
default: async ({ request }) => {
1212
const data = await request.formData();
13-
const title = data.get('title');
14-
const excerpt = data.get('excerpt');
15-
const slug = data.get('slug');
13+
const title = data.get('title')?.toString();
14+
const excerpt = data.get('excerpt')?.toString();
15+
const slug = data.get('slug')?.toString();
1616

1717
if (!title || !excerpt || !slug) {
1818
return { error: 'All fields are required' };
1919
}
2020
try {
2121
await prisma.blogPost.create({
2222
data: {
23-
title,
24-
excerpt,
25-
slug,
23+
title: title,
24+
excerpt: excerpt,
25+
slug: slug,
2626
seoTitle:"",
2727
seoDescription: "",
2828
draft: true
2929
}
3030
});
3131
return { success: true };
3232
} catch (e) {
33-
return { error: e?.message || 'Error creating blog' };
33+
return { error: /** @type {any} */ (e)?.message || 'Error creating blog' };
3434
}
3535
}
3636
};

0 commit comments

Comments
 (0)