feat: Add company linking to personal contacts
- Add companyId column to personal_contacts table - Update personal-contact service to include companyName in list - Add getContactsByCompanyId function for company contacts endpoint - Add GET /companies/:companyId/contacts endpoint - Add companyId to contact validation schema 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ const normalizePayload = (body) => ({
|
||||
phone: body.phone?.trim(),
|
||||
email: body.email?.trim(),
|
||||
secondaryEmail: body.secondaryEmail?.trim() || null,
|
||||
companyId: body.companyId || null,
|
||||
})
|
||||
|
||||
export const listPersonalContacts = async (req, res, next) => {
|
||||
@@ -57,3 +58,13 @@ export const deletePersonalContact = async (req, res, next) => {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
export const getContactsByCompany = async (req, res, next) => {
|
||||
try {
|
||||
const { companyId } = req.params
|
||||
const contacts = await personalContactService.getContactsByCompanyId(companyId)
|
||||
res.status(200).json({ success: true, data: contacts })
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +79,11 @@ export const contacts = pgTable('contacts', {
|
||||
accountEmailUnique: unique('account_email_unique').on(table.emailAccountId, table.email),
|
||||
}));
|
||||
|
||||
// Personal contacts - osobné kontakty používateľa (bez väzby na firmu alebo email account)
|
||||
// Personal contacts - osobné kontakty používateľa (s voliteľnou väzbou na firmu)
|
||||
export const personalContacts = pgTable('personal_contacts', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
|
||||
companyId: uuid('company_id').references(() => companies.id, { onDelete: 'set null' }), // voliteľná väzba na firmu
|
||||
firstName: text('first_name').notNull(),
|
||||
lastName: text('last_name'),
|
||||
phone: text('phone').notNull(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import express from 'express';
|
||||
import * as companyController from '../controllers/company.controller.js';
|
||||
import * as personalContactController from '../controllers/personal-contact.controller.js';
|
||||
import { authenticate } from '../middlewares/auth/authMiddleware.js';
|
||||
import { requireAdmin } from '../middlewares/auth/roleMiddleware.js';
|
||||
import { checkCompanyAccess } from '../middlewares/auth/resourceAccessMiddleware.js';
|
||||
@@ -188,4 +189,12 @@ router.delete(
|
||||
companyController.removeUserFromCompany
|
||||
);
|
||||
|
||||
// Company Contacts (Personal contacts linked to company)
|
||||
router.get(
|
||||
'/:companyId/contacts',
|
||||
validateParams(z.object({ companyId: z.string().uuid() })),
|
||||
checkCompanyAccess,
|
||||
personalContactController.getContactsByCompany
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -12,6 +12,7 @@ const createContactSchema = z.object({
|
||||
phone: z.string().min(3, 'Telefón je povinný'),
|
||||
email: z.string().email('Neplatný email'),
|
||||
secondaryEmail: z.union([z.string().email('Neplatný email'), z.literal('')]).optional(),
|
||||
companyId: z.union([z.string().uuid(), z.literal(''), z.null()]).optional(),
|
||||
})
|
||||
|
||||
const updateContactSchema = createContactSchema.partial()
|
||||
|
||||
@@ -1,13 +1,36 @@
|
||||
import { db } from '../config/database.js'
|
||||
import { personalContacts } from '../db/schema.js'
|
||||
import { personalContacts, companies } from '../db/schema.js'
|
||||
import { eq, and, desc, ne } from 'drizzle-orm'
|
||||
import { ConflictError, NotFoundError } from '../utils/errors.js'
|
||||
|
||||
export const listPersonalContacts = async (userId) => {
|
||||
const contacts = await db
|
||||
.select({
|
||||
id: personalContacts.id,
|
||||
userId: personalContacts.userId,
|
||||
companyId: personalContacts.companyId,
|
||||
firstName: personalContacts.firstName,
|
||||
lastName: personalContacts.lastName,
|
||||
phone: personalContacts.phone,
|
||||
email: personalContacts.email,
|
||||
secondaryEmail: personalContacts.secondaryEmail,
|
||||
createdAt: personalContacts.createdAt,
|
||||
updatedAt: personalContacts.updatedAt,
|
||||
companyName: companies.name,
|
||||
})
|
||||
.from(personalContacts)
|
||||
.leftJoin(companies, eq(personalContacts.companyId, companies.id))
|
||||
.where(eq(personalContacts.userId, userId))
|
||||
.orderBy(desc(personalContacts.updatedAt))
|
||||
|
||||
return contacts
|
||||
}
|
||||
|
||||
export const getContactsByCompanyId = async (companyId) => {
|
||||
return db
|
||||
.select()
|
||||
.from(personalContacts)
|
||||
.where(eq(personalContacts.userId, userId))
|
||||
.where(eq(personalContacts.companyId, companyId))
|
||||
.orderBy(desc(personalContacts.updatedAt))
|
||||
}
|
||||
|
||||
@@ -40,6 +63,7 @@ export const createPersonalContact = async (userId, contact) => {
|
||||
.insert(personalContacts)
|
||||
.values({
|
||||
userId,
|
||||
companyId: contact.companyId || null,
|
||||
firstName: contact.firstName,
|
||||
lastName: contact.lastName || null,
|
||||
phone: contact.phone,
|
||||
@@ -79,6 +103,7 @@ export const updatePersonalContact = async (contactId, userId, updates) => {
|
||||
if (updates.phone !== undefined) updateData.phone = updates.phone
|
||||
if (updates.email !== undefined) updateData.email = updates.email
|
||||
if (updates.secondaryEmail !== undefined) updateData.secondaryEmail = updates.secondaryEmail
|
||||
if (updates.companyId !== undefined) updateData.companyId = updates.companyId || null
|
||||
|
||||
const [updated] = await db
|
||||
.update(personalContacts)
|
||||
|
||||
Reference in New Issue
Block a user