feat: facility and google review crud

This commit is contained in:
Kailasdevdas
2026-06-25 16:59:11 +05:30
parent a88d2e3d8c
commit 99601f9f0d
17 changed files with 2293 additions and 2 deletions
+4
View File
@@ -19,6 +19,8 @@ import healthCheckRoutes from './routes/healthCheck.route.js';
import homepageBannerRoutes from './routes/homepageBanner.routes.js';
import insurancePartnerRoutes from './routes/insurancePartner.routes.js';
import accreditationRoutes from './routes/accreditation.routes.js';
import facilityRoutes from './routes/facility.routes.js';
import gReviewRoutes from './routes/googleReview.routes.js';
dotenv.config();
@@ -63,6 +65,8 @@ app.use('/api/health-check', healthCheckRoutes);
app.use('/api/homepage-banners', homepageBannerRoutes);
app.use('/api/insurance-partners', insurancePartnerRoutes);
app.use('/api/accreditation', accreditationRoutes);
app.use('/api/facilities', facilityRoutes);
app.use('/api/google-reviews', gReviewRoutes);
const PORT = process.env.PORT || 5008;
app.listen(PORT, () => {
@@ -0,0 +1,421 @@
import prisma from '../prisma/client.js';
export const getAllFacilities = async (req, res) => {
try {
const { admin } = req.query;
const facilities = await prisma.facility.findMany({
where: admin === 'true' ? {} : { isActive: true },
include: {
seo: true,
department: true,
images: true,
},
orderBy: [{ sortOrder: 'asc' }, { name: 'asc' }],
});
const formatted = facilities.map((fac, index) => ({
SL_NO: String(index + 1),
id: fac.id,
facilityId: fac.facilityId,
name: fac.name,
slug: fac.slug,
shortDescription: fac.shortDescription,
description: fac.description,
videoUrl: fac.videoUrl ?? '',
isActive: fac.isActive,
isFeatured: fac.isFeatured,
sortOrder: fac.sortOrder,
department: fac.department
? {
id: fac.department.id,
departmentId: fac.department.departmentId,
name: fac.department.name,
}
: null,
images: fac.images.map((img) => ({
id: img.id,
url: img.url,
altText: img.altText ?? '',
description: img.description ?? '',
})),
seo: {
seoTitle: fac.seo?.seoTitle ?? '',
metaDescription: fac.seo?.metaDescription ?? '',
focusKeyphrase: fac.seo?.focusKeyphrase ?? '',
slug: fac.seo?.slug ?? '',
tags: fac.seo?.tags ?? [],
ogTitle: fac.seo?.ogTitle ?? '',
ogDescription: fac.seo?.ogDescription ?? '',
ogImage: fac.seo?.ogImage ?? '',
},
}));
res.status(200).json({
success: true,
data: formatted,
});
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: 'Failed to fetch facilities',
});
}
};
export const getFacilityByFacilityId = async (req, res) => {
try {
const { facilityId } = req.params;
const { admin } = req.query;
const facility = await prisma.facility.findFirst({
where: {
facilityId,
...(admin === 'true' ? {} : { isActive: true }),
},
include: {
seo: true,
department: true,
images: true,
},
});
if (!facility) {
return res.status(404).json({
success: false,
message: 'Facility not found',
});
}
const response = {
facilityId: facility.facilityId,
name: facility.name,
slug: facility.slug,
shortDescription: facility.shortDescription,
description: facility.description,
videoUrl: facility.videoUrl ?? '',
isActive: facility.isActive,
isFeatured: facility.isFeatured,
sortOrder: facility.sortOrder,
department: facility.department
? {
departmentId: facility.department.departmentId,
name: facility.department.name,
}
: null,
images: facility.images.map((img) => ({
id: img.id,
url: img.url,
altText: img.altText ?? '',
description: img.description ?? '',
})),
seo: {
seoTitle: facility.seo?.seoTitle ?? '',
metaDescription: facility.seo?.metaDescription ?? '',
focusKeyphrase: facility.seo?.focusKeyphrase ?? '',
slug: facility.seo?.slug ?? '',
tags: facility.seo?.tags ?? [],
ogTitle: facility.seo?.ogTitle ?? '',
ogDescription: facility.seo?.ogDescription ?? '',
ogImage: facility.seo?.ogImage ?? '',
},
};
res.status(200).json({
success: true,
data: response,
});
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: 'Failed to fetch facility',
});
}
};
export const createFacility = async (req, res) => {
try {
const {
facilityId,
name,
slug,
shortDescription,
description,
videoUrl,
isActive,
isFeatured,
sortOrder,
departmentId,
images,
seoTitle,
metaDescription,
focusKeyphrase,
tags,
ogTitle,
ogDescription,
ogImage,
} = req.body;
const messages = [];
if (!facilityId) messages.push('Facility ID is required');
if (!name?.trim()) messages.push('Facility name is required');
if (!slug?.trim()) messages.push('Slug is required');
if (messages.length > 0) {
return res.status(400).json({
success: false,
message: messages.join(', '),
});
}
let dbDepartmentId = null;
if (departmentId) {
const targetDept = await prisma.department.findUnique({
where: { departmentId: departmentId },
});
if (targetDept) {
dbDepartmentId = targetDept.id;
}
}
const seo = await prisma.seo.create({
data: {
seoTitle,
metaDescription,
focusKeyphrase,
slug: slug ? slug : null,
tags: tags || [],
ogTitle,
ogDescription,
ogImage,
},
});
const facility = await prisma.facility.create({
data: {
facilityId,
name,
slug,
shortDescription,
description,
videoUrl,
isActive: isActive !== undefined ? isActive : true,
isFeatured: isFeatured !== undefined ? isFeatured : false,
sortOrder: sortOrder !== undefined ? Number(sortOrder) : 1000,
departmentId: dbDepartmentId,
seoId: seo.id,
},
});
if (images && images.length > 0) {
await prisma.facilityImage.createMany({
data: images.map((img) => ({
url: img.url,
altText: img.altText || null,
description: img.description || null,
facilityId: facility.id,
})),
});
}
res.status(201).json({
success: true,
message: 'Facility created successfully',
});
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: 'Failed to create facility',
});
}
};
export const updateFacility = async (req, res) => {
try {
const { facilityId, action } = req.params;
const {
name,
slug,
shortDescription,
description,
videoUrl,
isActive,
isFeatured,
sortOrder,
departmentId,
images,
seoTitle,
metaDescription,
focusKeyphrase,
tags,
ogTitle,
ogDescription,
ogImage,
} = req.body;
if (!facilityId) {
return res.status(400).json({ success: false, message: 'Facility ID is required' });
}
const facility = await prisma.facility.findUnique({ where: { facilityId } });
if (!facility) return res.status(404).json({ success: false, message: 'Facility not found' });
if (action === 'toggleStatus') {
await prisma.facility.update({
where: { id: facility.id },
data: { isActive: !facility.isActive },
});
return res.status(200).json({
success: true,
message: `Facility has been ${facility.isActive ? 'deactivated' : 'activated'} successfully`,
});
}
if (action === 'toggleFeatured') {
await prisma.facility.update({
where: { id: facility.id },
data: { isFeatured: !facility.isFeatured },
});
return res.status(200).json({
success: true,
message: `Facility has been ${facility.isFeatured ? 'removed from featured' : 'marked as featured'} successfully`,
});
}
const messages = [];
if (!name?.trim()) messages.push('Facility name is required');
if (!slug?.trim()) messages.push('Slug is required');
if (messages.length > 0) {
return res.status(400).json({ success: false, message: messages.join(', ') });
}
let dbDepartmentId = undefined;
if (departmentId !== undefined) {
if (departmentId) {
const targetDept = await prisma.department.findUnique({
where: { departmentId: departmentId },
});
dbDepartmentId = targetDept ? targetDept.id : null;
} else {
dbDepartmentId = null;
}
}
await prisma.facility.update({
where: { id: facility.id },
data: {
name,
slug,
shortDescription,
description,
videoUrl,
isActive: isActive !== undefined ? isActive : undefined,
isFeatured: isFeatured !== undefined ? isFeatured : undefined,
sortOrder: sortOrder !== undefined ? Number(sortOrder) : undefined,
departmentId: dbDepartmentId,
},
});
if (facility.seoId) {
await prisma.seo.update({
where: { id: facility.seoId },
data: {
seoTitle,
metaDescription,
focusKeyphrase,
slug: slug ? slug : null,
tags: tags || [],
ogTitle,
ogDescription,
ogImage,
},
});
} else {
const seo = await prisma.seo.create({
data: {
seoTitle,
metaDescription,
focusKeyphrase,
slug: slug ? slug : null,
tags: tags || [],
ogTitle,
ogDescription,
ogImage,
},
});
await prisma.facility.update({ where: { id: facility.id }, data: { seoId: seo.id } });
}
if (Array.isArray(images)) {
await prisma.facilityImage.deleteMany({ where: { facilityId: facility.id } });
if (images.length > 0) {
await prisma.facilityImage.createMany({
data: images.map((img) => ({
url: img.url,
altText: img.altText || null,
description: img.description || null,
facilityId: facility.id,
})),
});
}
}
res.status(200).json({ success: true, message: 'Facility updated successfully' });
} catch (error) {
console.error('Update Error:', error);
res.status(500).json({ success: false, message: 'Failed to update facility' });
}
};
export const deleteFacility = async (req, res) => {
try {
const { facilityId } = req.params;
const facility = await prisma.facility.findUnique({ where: { facilityId } });
if (!facility) {
return res.status(404).json({ success: false, message: 'Facility not found' });
}
await prisma.facilityImage.deleteMany({ where: { facilityId: facility.id } });
await prisma.facility.delete({ where: { id: facility.id } });
res.status(200).json({
success: true,
message: 'Facility deleted successfully',
});
} catch (error) {
console.error(error);
res.status(500).json({ success: false, message: 'Failed to delete facility' });
}
};
export const getFeaturedFacilities = async (req, res) => {
try {
const facilities = await prisma.facility.findMany({
where: { isActive: true, isFeatured: true },
include: {
images: true,
department: true,
},
orderBy: [{ sortOrder: 'asc' }, { name: 'asc' }],
});
const data = facilities.map((fac) => ({
facilityId: fac.facilityId,
name: fac.name,
slug: fac.slug,
shortDescription: fac.shortDescription,
image: fac.images[0]?.url ?? '',
departmentName: fac.department?.name ?? '',
}));
res.status(200).json({ success: true, data });
} catch (error) {
console.error(error);
res.status(500).json({ success: false, message: 'Failed to fetch featured facilities' });
}
};
@@ -0,0 +1,224 @@
import prisma from '../prisma/client.js';
export const getFeaturedGoogleReviews = async (req, res) => {
try {
const reviews = await prisma.googleReview.findMany({
where: {
isActive: true,
isFeatured: true,
},
orderBy: {
sortOrder: 'asc',
},
});
res.json({
success: true,
data: reviews,
});
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: 'Failed to fetch featured Google reviews',
});
}
};
export const createGoogleReview = async (req, res) => {
try {
const {
reviewerName,
reviewerImage,
rating,
review,
reviewDate,
googleReviewUrl,
isFeatured,
isActive,
sortOrder,
} = req.body;
if (!reviewerName || !rating || !review) {
return res.status(400).json({
success: false,
message: 'Reviewer name, rating and review are required.',
});
}
const googleReview = await prisma.googleReview.create({
data: {
reviewerName,
reviewerImage,
rating: Number(rating),
review,
reviewDate: reviewDate ? new Date(reviewDate) : null,
googleReviewUrl,
isFeatured,
isActive,
sortOrder,
},
});
res.status(201).json({
success: true,
data: googleReview,
message: 'Google review created successfully',
});
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: 'Failed to create Google review',
});
}
};
export const getGoogleReviews = async (req, res) => {
try {
const reviews = await prisma.googleReview.findMany({
orderBy: {
sortOrder: 'asc',
},
});
res.json({
success: true,
data: reviews,
});
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: 'Failed to fetch Google reviews',
});
}
};
export const getActiveGoogleReviews = async (req, res) => {
try {
const reviews = await prisma.googleReview.findMany({
where: {
isActive: true,
},
orderBy: {
sortOrder: 'asc',
},
});
res.json({
success: true,
data: reviews,
});
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: 'Failed to fetch active Google reviews',
});
}
};
export const getGoogleReview = async (req, res) => {
try {
const { id } = req.params;
const review = await prisma.googleReview.findUnique({
where: {
id: Number(id),
},
});
if (!review) {
return res.status(404).json({
success: false,
message: 'Google review not found',
});
}
res.json({
success: true,
data: review,
});
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: 'Failed to fetch Google review',
});
}
};
export const updateGoogleReview = async (req, res) => {
try {
const { id } = req.params;
const {
reviewerName,
reviewerImage,
rating,
review,
reviewDate,
googleReviewUrl,
isFeatured,
isActive,
sortOrder,
} = req.body;
const dataToUpdate = {};
if (reviewerName !== undefined) dataToUpdate.reviewerName = reviewerName;
if (reviewerImage !== undefined) dataToUpdate.reviewerImage = reviewerImage;
if (rating !== undefined) dataToUpdate.rating = Number(rating);
if (review !== undefined) dataToUpdate.review = review;
if (reviewDate !== undefined) {
dataToUpdate.reviewDate = reviewDate ? new Date(reviewDate) : null;
}
if (googleReviewUrl !== undefined) dataToUpdate.googleReviewUrl = googleReviewUrl;
if (isFeatured !== undefined) dataToUpdate.isFeatured = isFeatured;
if (isActive !== undefined) dataToUpdate.isActive = isActive;
if (sortOrder !== undefined) dataToUpdate.sortOrder = sortOrder;
const googleReview = await prisma.googleReview.update({
where: {
id: Number(id),
},
data: dataToUpdate,
});
res.json({
success: true,
data: googleReview,
message: 'Google review updated successfully',
});
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: 'Failed to update Google review',
});
}
};
export const deleteGoogleReview = async (req, res) => {
try {
const { id } = req.params;
await prisma.googleReview.delete({
where: {
id: Number(id),
},
});
res.json({
success: true,
message: 'Google review deleted successfully',
});
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: 'Failed to delete Google review',
});
}
};
+23
View File
@@ -0,0 +1,23 @@
import express from 'express';
import {
getAllFacilities,
getFacilityByFacilityId,
createFacility,
updateFacility,
deleteFacility,
getFeaturedFacilities,
} from '../controllers/facility.controller.js';
import jwtAuthMiddleware from '../middleware/auth.js';
const router = express.Router();
router.get('/getAll', getAllFacilities);
router.get('/featured', getFeaturedFacilities);
router.get('/:facilityId', getFacilityByFacilityId);
router.post('/', jwtAuthMiddleware, createFacility);
router.patch('/:facilityId/:action', jwtAuthMiddleware, updateFacility);
router.delete('/:facilityId', jwtAuthMiddleware, deleteFacility);
export default router;
+25
View File
@@ -0,0 +1,25 @@
import express from 'express';
import jwtAuthMiddleware from '../middleware/auth.js';
import {
createGoogleReview,
getGoogleReviews,
getActiveGoogleReviews,
getFeaturedGoogleReviews,
getGoogleReview,
updateGoogleReview,
deleteGoogleReview,
} from '../controllers/googleReview.controller.js';
const router = express.Router();
router.get('/active', getActiveGoogleReviews);
router.get('/featured', getFeaturedGoogleReviews);
router.post('/', jwtAuthMiddleware, createGoogleReview);
router.get('/getAll', jwtAuthMiddleware, getGoogleReviews);
router.get('/:id', jwtAuthMiddleware, getGoogleReview);
router.put('/:id', jwtAuthMiddleware, updateGoogleReview);
router.delete('/:id', jwtAuthMiddleware, deleteGoogleReview);
export default router;