Skip to content
This repository was archived by the owner on Nov 29, 2025. It is now read-only.
Merged

Dev #16

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@
"dependencies": {
"@fortawesome/free-brands-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@lucide/svelte": "^0.511.0",
"@prisma/client": "6.5.0",
"axios": "^1.8.4",
"date-fns": "^4.1.0",
"flowbite-svelte-blocks": "^1.1.4",
"flowbite-svelte-icons": "^2.1.1",
"marked": "^15.0.8",
"svelte-fa": "^4.0.3",
"uuid": "^11.1.0"
"uuid": "^11.1.0",
"zod": "^3.25.28"
}
}
20 changes: 20 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions prisma/migrations/20250524154126_/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "Comment" ADD COLUMN "taskId" TEXT;

-- AddForeignKey
ALTER TABLE "Comment" ADD CONSTRAINT "Comment_taskId_fkey" FOREIGN KEY ("taskId") REFERENCES "Task"("id") ON DELETE SET NULL ON UPDATE CASCADE;
7 changes: 5 additions & 2 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ model User {
contacts Contact[]
leads Lead[]
opportunities Opportunity[]
tasks Task[]
events Event[]
tasks Task[] // Tasks created by user
events Event[] // Events created by user
ownedTasks Task[] @relation("TaskOwner")
ownedEvents Event[] @relation("EventOwner")
cases Case[]
Expand Down Expand Up @@ -281,6 +281,7 @@ model Task {
caseId String?
organization Organization @relation(fields: [organizationId], references: [id])
organizationId String
comments Comment[] @relation("TaskComments")
}

model Event {
Expand Down Expand Up @@ -404,6 +405,8 @@ model Comment {
accountId String?
contact Contact? @relation(fields: [contactId], references: [id])
contactId String?
task Task? @relation("TaskComments", fields: [taskId], references: [id])
taskId String?
}

model Quote {
Expand Down
16 changes: 15 additions & 1 deletion src/routes/(app)/Sidebar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { afterNavigate } from '$app/navigation';
import { page } from '$app/stores';
import Fa from 'svelte-fa';
import { faPieChart } from '@fortawesome/free-solid-svg-icons';
import { faPieChart, faQuestion } from '@fortawesome/free-solid-svg-icons';
import {
Sidebar,
SidebarDropdownItem,
Expand Down Expand Up @@ -134,6 +134,20 @@
class={`${mainSidebarUrl === '/app/invoices/new' ? 'bg-gray-100 font-semibold dark:bg-gray-700' : ''}`}
/>
</SidebarDropdownWrapper> -->

<SidebarItem
label="Support"
href="/app/support"
class={`${mainSidebarUrl === '/app/support' ? 'flex p-2 items-center rounded-lg bg-gray-100 font-semibold dark:bg-gray-700' : ''}`}
spanClass="ml-3"
>
<svelte:fragment slot="icon">
<Fa
icon={faQuestion}
class={`${iconClass} ${mainSidebarUrl === '/app/support' ? 'text-gray-900 dark:text-white' : ''}`}
/>
</svelte:fragment>
</SidebarItem>
</SidebarGroup>

</nav>
Expand Down
7 changes: 4 additions & 3 deletions src/routes/(app)/app/accounts/+page.server.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { error } from '@sveltejs/kit';
import prisma from '$lib/prisma';

export async function load({ locals, url }) {

export async function load({ locals, url, params }) {
const org = locals.org;

const page = parseInt(url.searchParams.get('page') || '1');
const limit = parseInt(url.searchParams.get('limit') || '10');
const sort = url.searchParams.get('sort') || 'name';
Expand All @@ -12,7 +13,7 @@ export async function load({ locals, url }) {

try {
// Build the where clause for filtering
const where = {};
const where = {organizationId: org.id};

// Add status filter
const status = url.searchParams.get('status');
Expand Down
74 changes: 44 additions & 30 deletions src/routes/(app)/app/accounts/[accountId]/+page.server.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import { error, fail } from '@sveltejs/kit';
import prisma from '$lib/prisma';

/** @type {import('./$types').PageServerLoad} */
export async function load({ params, url }) {
export async function load({ params, url, locals }) {
const user = locals.user;
const org = locals.org;
try {
const accountId = params.accountId;

// Fetch account details
const account = await prisma.account.findUnique({
where: {
id: accountId
id: accountId,
organizationId: org.id
}
});

Expand Down Expand Up @@ -127,10 +130,7 @@ export const actions = {
closeAccount: async ({ params, request, locals }) => {
try {
const user = locals.user;

if (!user) {
return fail(401, { success: false, message: 'Unauthorized' });
}
const org = locals.org;

const { accountId } = params;
const formData = await request.formData();
Expand All @@ -142,7 +142,7 @@ export const actions = {

// Fetch the account to verify it exists
const account = await prisma.account.findUnique({
where: { id: accountId },
where: { id: accountId, organizationId: org.id },
select: {
id: true,
closedAt: true,
Expand All @@ -169,8 +169,7 @@ export const actions = {

const hasPermission =
user.id === account.ownerId ||
userOrg?.role === 'ADMIN' ||
userOrg?.role === 'SALES_MANAGER';
userOrg?.role === 'ADMIN';

if (!hasPermission) {
return fail(403, { success: false, message: 'Permission denied. Only account owners, sales managers, or admins can close accounts.' });
Expand Down Expand Up @@ -210,16 +209,13 @@ export const actions = {
reopenAccount: async ({ params, request, locals }) => {
try {
const user = locals.user;

if (!user) {
return fail(401, { success: false, message: 'Unauthorized' });
}
const org = locals.org;

const { accountId } = params;

// Fetch the account to verify it exists
const account = await prisma.account.findUnique({
where: { id: accountId },
where: { id: accountId, organizationId: org.id },
select: {
id: true,
closedAt: true,
Expand Down Expand Up @@ -247,8 +243,7 @@ export const actions = {

const hasPermission =
user.id === account.ownerId ||
userOrg?.role === 'ADMIN' ||
userOrg?.role === 'SALES_MANAGER';
userOrg?.role === 'ADMIN';

if (!hasPermission) {
return fail(403, { success: false, message: 'Permission denied. Only account owners, sales managers, or admins can reopen accounts.' });
Expand Down Expand Up @@ -294,9 +289,8 @@ export const actions = {
addContact: async ({ params, request, locals }) => {
try {
const user = locals.user;
if (!user) {
return fail(401, { success: false, message: 'Unauthorized' });
}
const org = locals.org;

const { accountId } = params;
let data;
// Support both JSON and form submissions
Expand All @@ -312,6 +306,14 @@ export const actions = {
if (!firstName || !lastName) {
return fail(400, { success: false, message: 'First and last name are required.' });
}

// check if the account exists and belongs to the organization
const account = await prisma.account.findUnique({
where: { id: accountId, organizationId: org.id }
});
if (!account) {
return fail(404, { success: false, message: 'Account not found or does not belong to this organization.' });
}
// Create the contact
const contact = await prisma.contact.create({
data: {
Expand All @@ -321,7 +323,7 @@ export const actions = {
phone: data.phone?.toString() || null,
title: data.title?.toString() || null,
ownerId: user.id,
organizationId: (await prisma.account.findUnique({ where: { id: accountId }, select: { organizationId: true } })).organizationId
organizationId: org.id,
}
});
// Link contact to account
Expand All @@ -342,13 +344,9 @@ export const actions = {

addOpportunity: async ({ params, request, locals }) => {
try {
// @ts-ignore
const user = locals.user;
// @ts-ignore
const org = locals.org;
if (!user || !org) {
return fail(401, { success: false, message: 'Unauthorized' });
}

const { accountId } = params;
const formData = await request.formData();
const name = formData.get('name')?.toString().trim();
Expand All @@ -363,6 +361,15 @@ export const actions = {
if (!name) {
return fail(400, { success: false, message: 'Opportunity name is required.' });
}

// chek if the account exists and belongs to the organization
const account = await prisma.account.findUnique({
where: { id: accountId, organizationId: org.id }
});
if (!account) {
return fail(404, { success: false, message: 'Account not found or does not belong to this organization.' });
}

// Create the opportunity
await prisma.opportunity.create({
data: {
Expand All @@ -385,9 +392,10 @@ export const actions = {

comment: async ({ request, params, locals }) => {
const user = locals.user;
const org = locals.org;
// Fallback: fetch account to get organizationId
const account = await prisma.account.findUnique({
where: { id: params.accountId },
where: { id: params.accountId, organizationId: org.id },
select: { organizationId: true, ownerId: true }
});
if (!account) {
Expand All @@ -414,9 +422,7 @@ export const actions = {
try {
const user = locals.user;
const org = locals.org;
if (!user || !org) {
return fail(401, { success: false, message: 'Unauthorized' });
}

const { accountId } = params;
const formData = await request.formData();
const subject = formData.get('subject')?.toString().trim();
Expand All @@ -427,9 +433,17 @@ export const actions = {
if (!subject) {
return fail(400, { success: false, message: 'Subject is required.' });
}

// Check if the account exists and belongs to the organization
const account = await prisma.account.findUnique({
where: { id: accountId, organizationId: org.id }
});
if (!account) {
return fail(404, { success: false, message: 'Account not found or does not belong to this organization.' });
}
// If no ownerId is provided, default to current user
// if (!ownerId) ownerId = user.id;
console.log(user.id, org.id);
// console.log(user.id, org.id);
const task = await prisma.task.create({
data: {
subject,
Expand Down
10 changes: 6 additions & 4 deletions src/routes/(app)/app/accounts/[accountId]/delete/+page.server.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import prisma from '$lib/prisma';
import { error, fail, redirect } from '@sveltejs/kit';

export async function load({ params }) {
export async function load({ params, locals }) {
const org = locals.org;
try {
const accountId = params.accountId;

const account = await prisma.account.findUnique({
where: { id: accountId },
where: { id: accountId, organizationId: org.id },
select: {
id: true,
name: true,
Expand Down Expand Up @@ -72,13 +73,14 @@ export async function load({ params }) {
}

export const actions = {
default: async ({ params }) => {
default: async ({ params, locals }) => {
try {
const accountId = params.accountId;
const org = locals.org;

// Check if account exists first
const account = await prisma.account.findUnique({
where: { id: accountId },
where: { id: accountId, organizationId: org.id },
include: {
_count: {
select: {
Expand Down
Loading