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 },
|
showPublicProfessionals: { type: Boolean, required: false, default: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.schema.index({ published: 1, banned: 1 });
|
||||||
|
|
||||||
this.companyList = model<ICompanyDocument>("Company", this.schema);
|
this.companyList = model<ICompanyDocument>("Company", this.schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { isNull } from "../../helpers/IsNull";
|
import { isNull } from "../../helpers/IsNull";
|
||||||
import CompaniesList from "../Companies/Companies";
|
import CompaniesList from "../Companies/Companies";
|
||||||
|
import { CompaniesAdapterMongoose } from "../Companies/Companies.Adapter.Mongoose";
|
||||||
import ServiceList from "../Services/Service";
|
import ServiceList from "../Services/Service";
|
||||||
import {
|
import {
|
||||||
PublicServicesResults,
|
PublicServicesResults,
|
||||||
@@ -15,6 +16,24 @@ import { BotEventParams, BotView } from "../WapServer/WapServer.Interface";
|
|||||||
import WapServerList from "../WapServer/WapServer";
|
import WapServerList from "../WapServer/WapServer";
|
||||||
import { COMPANY_PUBLISHED_STATUS } from "../Companies/Companies.Interface";
|
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 = {
|
export type HomeView = {
|
||||||
education: PublicServicesResults;
|
education: PublicServicesResults;
|
||||||
health: PublicServicesResults;
|
health: PublicServicesResults;
|
||||||
@@ -39,6 +58,7 @@ export type PublicOrganizationViewParams = {
|
|||||||
|
|
||||||
export type PublicOrganizationView = {
|
export type PublicOrganizationView = {
|
||||||
id: string;
|
id: string;
|
||||||
|
slug: string;
|
||||||
headerFile: string;
|
headerFile: string;
|
||||||
headerColor: string;
|
headerColor: string;
|
||||||
headerFontColor: string;
|
headerFontColor: string;
|
||||||
@@ -143,6 +163,7 @@ class Views {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
id: isNull<string>(company.id, ""),
|
id: isNull<string>(company.id, ""),
|
||||||
|
slug: isNull<string>(company.slug, ""),
|
||||||
name: isNull<string>(company.name, ""),
|
name: isNull<string>(company.name, ""),
|
||||||
description: isNull<string>(company.description, ""),
|
description: isNull<string>(company.description, ""),
|
||||||
categoryId: isNull<number>(company.categoryId, 50000),
|
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> {
|
public async wapView(data: BotEventParams): Promise<BotView> {
|
||||||
return await WapServerList.botView(data);
|
return await WapServerList.botView(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import {
|
|||||||
PublicOrganizationServiceView,
|
PublicOrganizationServiceView,
|
||||||
UserAppointmentViewParams,
|
UserAppointmentViewParams,
|
||||||
UserAppointmentView,
|
UserAppointmentView,
|
||||||
|
PublicOrganizationsParams,
|
||||||
|
PublicOrganizationsResult,
|
||||||
} from "../../Models/Views/Views";
|
} from "../../Models/Views/Views";
|
||||||
import { ViewsService } from "./Views.Service";
|
import { ViewsService } from "./Views.Service";
|
||||||
import { BotEventParams, BotView } from "../../Models/WapServer/WapServer.Interface";
|
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,
|
PublicOrganizationServiceView,
|
||||||
UserAppointmentViewParams,
|
UserAppointmentViewParams,
|
||||||
UserAppointmentView,
|
UserAppointmentView,
|
||||||
|
PublicOrganizationsParams,
|
||||||
|
PublicOrganizationsResult,
|
||||||
} from "../../Models/Views/Views";
|
} from "../../Models/Views/Views";
|
||||||
import { BotView, BotEventParams } from "../../Models/WapServer/WapServer.Interface";
|
import { BotView, BotEventParams } from "../../Models/WapServer/WapServer.Interface";
|
||||||
|
|
||||||
@@ -45,4 +47,12 @@ export class ViewsService {
|
|||||||
const view = await views.wapView(data);
|
const view = await views.wapView(data);
|
||||||
return view;
|
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 { PublicOrganizationView } from "@core/Models/Company.model";
|
||||||
import OrganizationHeader from "@core/app/components/Home/OrganizationHeader/OrganizationHeader";
|
import OrganizationHeader from "@core/app/components/Home/OrganizationHeader/OrganizationHeader";
|
||||||
import OrganizationDataConnector from "./components/OrganizationData";
|
import OrganizationDataConnector from "./components/OrganizationData";
|
||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
const GetOrganizationData = async (companyId: string): Promise<PublicOrganizationView> => {
|
const GetOrganizationData = async (companyId: string): Promise<PublicOrganizationView> => {
|
||||||
try {
|
try {
|
||||||
@@ -28,6 +29,49 @@ type Props = {
|
|||||||
children: React.ReactNode;
|
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) {
|
export default async function OrganizationPublicProfile({ params, children }: Props) {
|
||||||
const { oid } = await params;
|
const { oid } = await params;
|
||||||
const orgData = await GetOrganizationData(oid);
|
const orgData = await GetOrganizationData(oid);
|
||||||
|
|||||||
@@ -165,7 +165,44 @@ export async function GET() {
|
|||||||
console.error("Error generating sitemap:", error);
|
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"?>
|
const sitemapXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||||
|
|||||||
Reference in New Issue
Block a user