add: crud contact

This commit is contained in:
2025-11-12 14:22:08 +07:00
parent 93b6b1b15e
commit d2d6ce2ab1
6 changed files with 318 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
const ContactService = require('../services/contact.service');
const { setResponse, setResponsePaging, checkValidate } = require('../helpers/utils');
const { insertContactSchema, updateContactSchema } = require('../validate/contact.schema');
class ContactController {
// Get all contact
static async getAll(req, res) {
const queryParams = req.query;
const results = await ContactService.getAllContact(queryParams);
const response = await setResponsePaging(queryParams, results, 'Contact found')
res.status(response.statusCode).json(response);
}
// Get contact by ID
static async getById(req, res) {
const { id } = req.params;
const results = await ContactService.getContactById(id);
const response = await setResponse(results, 'Contact found')
res.status(response.statusCode).json(response);
}
// Create contact
static async create(req, res) {
const { error, value } = await checkValidate(insertContactSchema, req)
if (error) {
return res.status(400).json(setResponse(error, 'Validation failed', 400));
}
value.userId = req.user.user_id
const results = await ContactService.createContact(value);
const response = await setResponse(results, 'Contact created successfully')
return res.status(response.statusCode).json(response);
}
// Update contact
static async update(req, res) {
const { id } = req.params;
const { error, value } = checkValidate(updateContactSchema, req)
if (error) {
return res.status(400).json(setResponse(error, 'Validation failed', 400));
}
value.userId = req.user.user_id
const results = await ContactService.updateContact(id, value);
const response = await setResponse(results, 'Contact updated successfully')
res.status(response.statusCode).json(response);
}
// Soft delete contact
static async delete(req, res) {
const { id } = req.params;
const results = await ContactService.deleteContact(id, req.user.user_id);
const response = await setResponse(results, 'Contact deleted successfully')
res.status(response.statusCode).json(response);
}
}
module.exports = ContactController;

105
db/contact.db.js Normal file
View File

@@ -0,0 +1,105 @@
const pool = require("../config");
// Get all Contact
const getAllContactDb = async (searchParams = {}) => {
let queryParams = [];
if (searchParams.limit) {
const page = Number(searchParams.page ?? 1) - 1;
queryParams = [Number(searchParams.limit ?? 10), page];
}
const { whereOrConditions, whereParamOr } = pool.buildStringOrIlike(
[
"a.contact_name",
"a.contact_type",
],
searchParams.criteria,
queryParams
);
if (whereParamOr) queryParams = whereParamOr;
const { whereConditions, whereParamAnd } = pool.buildFilterQuery(
[
{ column: "a.contact_name", param: searchParams.name, type: "string" },
{ column: "a.contact_type", param: searchParams.code, type: "string" },
],
queryParams
);
if (whereParamAnd) queryParams = whereParamAnd;
const queryText = `
SELECT
COUNT(*) OVER() AS total_data,
a.*
FROM contact a
WHERE a.deleted_at IS NULL
${whereConditions.length > 0 ? ` AND ${whereConditions.join(" AND ")}` : ""}
${whereOrConditions ? ` ${whereOrConditions}` : ""}
ORDER BY a.contact_id ASC
${searchParams.limit ? `OFFSET $2 * $1 ROWS FETCH NEXT $1 ROWS ONLY` : ''}
`;
const result = await pool.query(queryText, queryParams);
const total =
result?.recordset?.length > 0
? parseInt(result.recordset[0].total_data, 10)
: 0;
return { data: result.recordset, total };
};
const getContactByIdDb = async (id) => {
const queryText = `
SELECT
a.*
FROM contact a
WHERE a.contact_id = $1 AND a.deleted_at IS NULL
`;
const result = await pool.query(queryText, [id]);
return result.recordset;
};
const createContactDb = async (store) => {
const { query: queryText, values } = pool.buildDynamicInsert("contact", store);
const result = await pool.query(queryText, values);
const insertedId = result.recordset?.[0]?.inserted_id;
return insertedId ? await getContactByIdDb(insertedId) : null;
};
const updateContactDb = async (id, data) => {
const store = { ...data };
const whereData = { contact_id: id };
const { query: queryText, values } = pool.buildDynamicUpdate(
"contact",
store,
whereData
);
await pool.query(`${queryText} AND deleted_at IS NULL`, values);
return getContactByIdDb(id);
};
// Soft delete tag
const deleteContactDb = async (id, deletedBy) => {
const queryText = `
UPDATE contact
SET deleted_at = CURRENT_TIMESTAMP, deleted_by = $1
WHERE contact_id = $2 AND deleted_at IS NULL
`;
await pool.query(queryText, [deletedBy, id]);
return true;
};
module.exports = {
getAllContactDb,
getContactByIdDb,
createContactDb,
updateContactDb,
deleteContactDb,
};

17
routes/contact.route.js Normal file
View File

@@ -0,0 +1,17 @@
const express = require('express');
const ContactController = require('../controllers/contact.controller');
const verifyToken = require("../middleware/verifyToken")
const verifyAccess = require("../middleware/verifyAccess")
const router = express.Router();
router.route("/")
.get(verifyToken.verifyAccessToken, ContactController.getAll)
.post(verifyToken.verifyAccessToken, verifyAccess(), ContactController.create);
router.route("/:id")
.get(verifyToken.verifyAccessToken, ContactController.getById)
.put(verifyToken.verifyAccessToken, verifyAccess(), ContactController.update)
.delete(verifyToken.verifyAccessToken, verifyAccess(), ContactController.delete);
module.exports = router;

View File

@@ -13,6 +13,7 @@ const status = require("./status.route");
const unit = require("./unit.route")
const UserSchedule = require("./user_schedule.route")
const historyValue = require("./history_value.route")
const contact = require("./contact.route")
router.use("/auth", auth);
router.use("/user", users);
@@ -28,6 +29,7 @@ router.use("/status", status);
router.use("/unit", unit);
router.use("/user-schedule", UserSchedule)
router.use("/history", historyValue)
router.use("/contact", contact)
module.exports = router;

View File

@@ -0,0 +1,88 @@
const {
getAllContactDb,
getContactByIdDb,
createContactDb,
updateContactDb,
deleteContactDb
} = require('../db/contact.db');
const { ErrorHandler } = require('../helpers/error');
class ContactService {
// Get all Contact
static async getAllContact(param) {
try {
const results = await getAllContactDb(param);
results.data.map(element => {
});
return results
} catch (error) {
throw new ErrorHandler(error.statusCode, error.message);
}
}
// Get Contact by ID
static async getContactById(id) {
try {
const result = await getContactByIdDb(id);
if (result.length < 1) throw new ErrorHandler(404, 'Contact not found');
return result;
} catch (error) {
throw new ErrorHandler(error.statusCode, error.message);
}
}
// Create Contact
static async createContact(data) {
try {
if (!data || typeof data !== 'object') data = {};
const result = await createContactDb(data);
return result;
} catch (error) {
throw new ErrorHandler(error.statusCode, error.message);
}
}
// Update Contact
static async updateContact(id, data) {
try {
if (!data || typeof data !== 'object') data = {};
const dataExist = await getContactByIdDb(id);
if (dataExist.length < 1) {
throw new ErrorHandler(404, 'Contact not found');
}
const result = await updateContactDb(id, data);
return result;
} catch (error) {
throw new ErrorHandler(error.statusCode, error.message);
}
}
// Soft delete Contact
static async deleteContact(id, userId) {
try {
const dataExist = await getContactByIdDb(id);
if (dataExist.length < 1) {
throw new ErrorHandler(404, 'Contact not found');
}
const result = await deleteContactDb(id, userId);
return result;
} catch (error) {
throw new ErrorHandler(error.statusCode, error.message);
}
}
}
module.exports = ContactService;

View File

@@ -0,0 +1,35 @@
const Joi = require("joi");
// ========================
// Contacts Validation
// ========================
const insertContactSchema = Joi.object({
contact_name: Joi.string().min(3).max(100).required(),
contact_phone: Joi.string()
.pattern(/^(?:\+62|0)8\d{7,10}$/)
.required()
.messages({
"string.pattern.base":
"Phone number must be a valid Indonesian number in format +628XXXXXXXXX",
}),
is_active: Joi.boolean().required(),
contact_type: Joi.string().max(255).required()
});
const updateContactSchema = Joi.object({
contact_name: Joi.string().min(3).max(100).required(),
contact_phone: Joi.string()
.pattern(/^(?:\+62|0)8\d{7,10}$/)
.required()
.messages({
"string.pattern.base":
"Phone number must be a valid Indonesian number in format +628XXXXXXXXX",
}),
is_active: Joi.boolean().optional(),
contact_type: Joi.string().max(255).optional()
});
module.exports = {
insertContactSchema,
updateContactSchema,
};