feat(agents): add public agent profile page at /agents/[id]

Implements a public-facing agent profile page with:
- Backend: new GET /agents/:agentId/profile public API endpoint with
  agent info, active listings, quality score, and review stats
- Frontend: server-rendered profile page with generateMetadata for SEO,
  JSON-LD structured data (RealEstateAgent schema), breadcrumbs
- Agent profile displays bio, service areas, quality score gauge,
  active listing cards, reviews with star ratings, and contact CTA
- Mobile responsive layout with sticky contact sidebar on desktop
- Vietnamese UI text throughout, consistent with existing patterns

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-11 00:16:19 +07:00
parent 37fab515b7
commit 62485fee98
13 changed files with 905 additions and 5 deletions

View File

@@ -40,7 +40,7 @@ describe('GoogleCallbackPage', () => {
handleOAuthCallback: vi.fn().mockResolvedValue(undefined),
};
mockedUseAuthStore.mockImplementation((selector) => {
if (typeof selector === 'function') return (selector as (s: typeof mockStore) => unknown)(mockStore);
if (typeof selector === 'function') return (selector as unknown as (s: typeof mockStore) => unknown)(mockStore);
return mockStore as ReturnType<typeof useAuthStore>;
});
});

View File

@@ -40,7 +40,7 @@ describe('ZaloCallbackPage', () => {
handleOAuthCallback: vi.fn().mockResolvedValue(undefined),
};
mockedUseAuthStore.mockImplementation((selector) => {
if (typeof selector === 'function') return (selector as (s: typeof mockStore) => unknown)(mockStore);
if (typeof selector === 'function') return (selector as unknown as (s: typeof mockStore) => unknown)(mockStore);
return mockStore as ReturnType<typeof useAuthStore>;
});
});