feat: agregar funcionalidad para obtener organizaciones públicas y actualizar el sitemap con rutas dinámicas
This commit is contained in:
@@ -72,6 +72,8 @@ export class CompaniesAdapterMongoose implements ICompaniesAdapter {
|
||||
showPublicProfessionals: { type: Boolean, required: false, default: true },
|
||||
});
|
||||
|
||||
this.schema.index({ published: 1, banned: 1 });
|
||||
|
||||
this.companyList = model<ICompanyDocument>("Company", this.schema);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { isNull } from "../../helpers/IsNull";
|
||||
import CompaniesList from "../Companies/Companies";
|
||||
import { CompaniesAdapterMongoose } from "../Companies/Companies.Adapter.Mongoose";
|
||||
import ServiceList from "../Services/Service";
|
||||
import {
|
||||
PublicServicesResults,
|
||||
@@ -15,6 +16,24 @@ import { BotEventParams, BotView } from "../WapServer/WapServer.Interface";
|
||||
import WapServerList from "../WapServer/WapServer";
|
||||
import { COMPANY_PUBLISHED_STATUS } from "../Companies/Companies.Interface";
|
||||
|
||||
export type PublicOrganizationsParams = {
|
||||
page: number;
|
||||
limit: number;
|
||||
};
|
||||
|
||||
export type PublicOrganizationListItem = {
|
||||
slug: string;
|
||||
name: string;
|
||||
description: string;
|
||||
creationDate: Date;
|
||||
};
|
||||
|
||||
export type PublicOrganizationsResult = {
|
||||
data: PublicOrganizationListItem[];
|
||||
page: number;
|
||||
pages: number;
|
||||
};
|
||||
|
||||
export type HomeView = {
|
||||
education: PublicServicesResults;
|
||||
health: PublicServicesResults;
|
||||
@@ -39,6 +58,7 @@ export type PublicOrganizationViewParams = {
|
||||
|
||||
export type PublicOrganizationView = {
|
||||
id: string;
|
||||
slug: string;
|
||||
headerFile: string;
|
||||
headerColor: string;
|
||||
headerFontColor: string;
|
||||
@@ -143,6 +163,7 @@ class Views {
|
||||
|
||||
return {
|
||||
id: isNull<string>(company.id, ""),
|
||||
slug: isNull<string>(company.slug, ""),
|
||||
name: isNull<string>(company.name, ""),
|
||||
description: isNull<string>(company.description, ""),
|
||||
categoryId: isNull<number>(company.categoryId, 50000),
|
||||
@@ -249,6 +270,44 @@ class Views {
|
||||
};
|
||||
}
|
||||
|
||||
public async publicOrganizations(
|
||||
data: PublicOrganizationsParams
|
||||
): Promise<PublicOrganizationsResult> {
|
||||
const { page, limit } = data;
|
||||
const filter = {
|
||||
published: COMPANY_PUBLISHED_STATUS.PUBLISHED,
|
||||
banned: { $ne: true },
|
||||
};
|
||||
|
||||
const companyList = (CompaniesList.companies as CompaniesAdapterMongoose).companyList;
|
||||
|
||||
const count = await companyList
|
||||
.countDocuments(filter)
|
||||
.exec();
|
||||
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
const results = (await companyList
|
||||
.find(filter)
|
||||
.select("slug name description creationDate")
|
||||
.sort({ creationDate: 1 })
|
||||
.skip(skip)
|
||||
.limit(limit)
|
||||
.lean()
|
||||
.exec()) as any[];
|
||||
|
||||
return {
|
||||
data: results.map((company) => ({
|
||||
slug: String(company.slug || ""),
|
||||
name: String(company.name || ""),
|
||||
description: String(company.description || ""),
|
||||
creationDate: company.creationDate,
|
||||
})),
|
||||
page,
|
||||
pages: Math.ceil(count / limit),
|
||||
};
|
||||
}
|
||||
|
||||
public async wapView(data: BotEventParams): Promise<BotView> {
|
||||
return await WapServerList.botView(data);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
PublicOrganizationServiceView,
|
||||
UserAppointmentViewParams,
|
||||
UserAppointmentView,
|
||||
PublicOrganizationsParams,
|
||||
PublicOrganizationsResult,
|
||||
} from "../../Models/Views/Views";
|
||||
import { ViewsService } from "./Views.Service";
|
||||
import { BotEventParams, BotView } from "../../Models/WapServer/WapServer.Interface";
|
||||
@@ -109,3 +111,23 @@ export class WapServerBotViewController extends Controller {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Route("views/public-organizations")
|
||||
export class PublicOrganizationsController extends Controller {
|
||||
@Response<ApiValidationError>(500, "Ha ocurrido un error")
|
||||
@SuccessResponse(200, "Done")
|
||||
@Post()
|
||||
public async publicOrganizations(
|
||||
@Body() requestBody: PublicOrganizationsParams
|
||||
): Promise<PublicOrganizationsResult | ApiValidationError> {
|
||||
try {
|
||||
const result = await new ViewsService().publicOrganizations(requestBody);
|
||||
this.setStatus(200);
|
||||
return result;
|
||||
} catch (e) {
|
||||
const errorOccurred: Error = e as Error;
|
||||
this.setStatus(500);
|
||||
return new ApiValidationError(500, errorOccurred.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import views, {
|
||||
PublicOrganizationServiceView,
|
||||
UserAppointmentViewParams,
|
||||
UserAppointmentView,
|
||||
PublicOrganizationsParams,
|
||||
PublicOrganizationsResult,
|
||||
} from "../../Models/Views/Views";
|
||||
import { BotView, BotEventParams } from "../../Models/WapServer/WapServer.Interface";
|
||||
|
||||
@@ -45,4 +47,12 @@ export class ViewsService {
|
||||
const view = await views.wapView(data);
|
||||
return view;
|
||||
}
|
||||
|
||||
public async publicOrganizations(
|
||||
data: PublicOrganizationsParams
|
||||
): Promise<PublicOrganizationsResult> {
|
||||
await connect(`${process.env.DATABASE_CONNECTION}`);
|
||||
const result = await views.publicOrganizations(data);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import ApiServerService from "@services/Api.Server.Service";
|
||||
import { PublicOrganizationView } from "@core/Models/Company.model";
|
||||
import OrganizationHeader from "@core/app/components/Home/OrganizationHeader/OrganizationHeader";
|
||||
import OrganizationDataConnector from "./components/OrganizationData";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
const GetOrganizationData = async (companyId: string): Promise<PublicOrganizationView> => {
|
||||
try {
|
||||
@@ -28,6 +29,49 @@ type Props = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export async function generateMetadata({ params }: { params: Promise<Params> }): Promise<Metadata> {
|
||||
const { oid } = await params;
|
||||
const orgData = await GetOrganizationData(oid);
|
||||
|
||||
if (!orgData || !orgData.id) {
|
||||
return {
|
||||
robots: { index: false, follow: false },
|
||||
};
|
||||
}
|
||||
|
||||
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "https://turnosxpress.com.ar";
|
||||
const canonicalUrl = `${baseUrl}/landing/org/${oid}`;
|
||||
const description =
|
||||
orgData.description && orgData.description.trim().length > 0
|
||||
? orgData.description
|
||||
: `${orgData.name} - TurnosXpress`;
|
||||
|
||||
return {
|
||||
title: `${orgData.name} | TurnosXpress`,
|
||||
description,
|
||||
alternates: {
|
||||
canonical: canonicalUrl,
|
||||
},
|
||||
openGraph: {
|
||||
type: "website",
|
||||
title: `${orgData.name} | TurnosXpress`,
|
||||
description,
|
||||
url: canonicalUrl,
|
||||
siteName: "TurnosXpress",
|
||||
locale: "es_AR",
|
||||
},
|
||||
twitter: {
|
||||
card: "summary",
|
||||
title: `${orgData.name} | TurnosXpress`,
|
||||
description,
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default async function OrganizationPublicProfile({ params, children }: Props) {
|
||||
const { oid } = await params;
|
||||
const orgData = await GetOrganizationData(oid);
|
||||
|
||||
@@ -165,7 +165,44 @@ export async function GET() {
|
||||
console.error("Error generating sitemap:", error);
|
||||
}
|
||||
|
||||
const allRoutes = [...staticRoutes, ...videoRoutes, ...authRoutes, ...marketingRoutes, ...explorationRoutes, ...legalRoutes, ...serviceRoutes];
|
||||
let orgRoutes: SitemapRoute[] = [];
|
||||
|
||||
try {
|
||||
let currentPage = 1;
|
||||
let totalPages = 1;
|
||||
|
||||
do {
|
||||
const orgsResult = await ApiServerService.post<{
|
||||
data: { slug: string; name: string; description: string; creationDate?: string }[];
|
||||
page: number;
|
||||
pages: number;
|
||||
}>("views/public-organizations", {
|
||||
page: currentPage,
|
||||
limit: 1000,
|
||||
});
|
||||
|
||||
if (orgsResult && orgsResult.data) {
|
||||
totalPages = orgsResult.pages || 1;
|
||||
|
||||
const newRoutes = orgsResult.data.map((org) => ({
|
||||
url: `${baseUrl}/landing/org/${org.slug}`,
|
||||
changeFrequency: "weekly" as const,
|
||||
priority: 0.8,
|
||||
}));
|
||||
|
||||
orgRoutes = [...orgRoutes, ...newRoutes];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
currentPage++;
|
||||
} while (currentPage <= totalPages);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error generating org sitemap:", error);
|
||||
}
|
||||
|
||||
const allRoutes = [...staticRoutes, ...videoRoutes, ...authRoutes, ...marketingRoutes, ...orgRoutes, ...explorationRoutes, ...legalRoutes, ...serviceRoutes];
|
||||
|
||||
const sitemapXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
|
||||
Reference in New Issue
Block a user