Skip to content

Commit

Permalink
website page feature
Browse files Browse the repository at this point in the history
  • Loading branch information
upiksaleh committed Nov 22, 2024
1 parent aae5bdc commit d27706c
Show file tree
Hide file tree
Showing 12 changed files with 292 additions and 2 deletions.
46 changes: 46 additions & 0 deletions src/app/website/[subdomain]/page/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { notFound } from 'next/navigation';
import { Metadata } from 'next';
import { dataSiteBySubdomain, dataSitePageBySlug } from '@/lib/data/site';
import { TWebsitePageProps } from '@/types';
import SitePage from '@/components/website/page';

export async function generateMetadata(
props: TWebsitePageProps<{ slug: string }>
): Promise<Metadata> {
const {
params: { subdomain, slug },
} = props;
const site = await dataSiteBySubdomain(subdomain);
if (!site) notFound();
const item = await dataSitePageBySlug(site.id, slug);
if (!item) notFound();

return {
title: item.title,
description: item.description ?? site.name,
};
}
export default async function Page(props: TWebsitePageProps<{ slug: string }>) {
const {
params: { subdomain, slug },
} = props;
const site = await dataSiteBySubdomain(subdomain);
if (!site) notFound();
const item = await dataSitePageBySlug(site.id, slug);
if (!item) notFound();

return (
<>
<SitePage
site={site}
data={{ item }}
page={{
...props,
name: 'page/[slug]',
title: item.title,
subTitle: item.description ?? '',
}}
/>
</>
);
}
6 changes: 4 additions & 2 deletions src/components/share/item-news.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ import { useEffect, useState } from 'react';

export default function NewsShareItem({
item,
isPage,
...props
}: Partial<ShareItemProps> & {
item: TNewsOrWebNewsItemBySlug;
isPage?: true;
}) {
const [url, setUrl] = useState('');
useEffect(() => {
setUrl(`${window.origin}/berita/${item.slug}`);
}, [item]);
setUrl(`${window.origin}/${isPage ? 'page' : 'berita'}/${item.slug}`);
}, [item, isPage]);
return (
<ShareItem
url={url}
Expand Down
1 change: 1 addition & 0 deletions src/components/website/templates/base/pages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ const pages = {
dokumen: dynamic(() => import('./dokumen/page')),
'dokumen/[slug]': dynamic(() => import('./dokumen/[slug]/page')),
'profil/[slug]': dynamic(() => import('./profil/[slug]/page')),
'page/[slug]': dynamic(() => import('./page/[slug]/page')),
};
export default pages;
54 changes: 54 additions & 0 deletions src/components/website/templates/base/pages/page/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import BlurImage from '@/components/blur-image';
import ContentBlocks from '@/components/content-blocks';
import BaseIcon from '@/components/icons/base-icon';
import NewsShareItem from '@/components/share/item-news';
import { SiteContextType } from '@/components/website/provider';
import { TWebPageItemBySlug } from '@/types';

export default function Page({
data: { item },
site,
}: SiteContextType<{ slug: string }, { item: TWebPageItemBySlug }>) {
return (
<article className="px-5">
<section className="h-full grid grid-cols-1 gap-8 lg:grid-cols-[70%,25%] xl:gap-[72px]">
<div className="flex flex-col gap-7">
<div className="w-full min-h-screen">
<div className="flex flex-col gap-2 mt-3">
{item.image_cover && (
<BlurImage
src={item.image_cover.url}
alt={item.title}
width="0"
height="0"
sizes="100vw"
className="image-zoom w-full h-full rounded-lg"
/>
)}
</div>
{item.content && item.content.blocks && (
<div className="prose max-w-none">
<ContentBlocks {...item.content} />
</div>
)}
</div>
<p className="font-lora text-gray-800"></p>
</div>
<div className="my-5 w-full">
<div className="flex flex-col gap-2 lg:sticky lg:top-[88px] w-full overflow-auto">
<div className="flex flex-col gap-3 mb-5 overflow-y-auto">
<p className="inline-flex gap-3 font-lato text-xs text-blue-gray-200 leading-5">
<BaseIcon
icon="share"
className="self-start text-primary w-5 h-5"
/>
Bagikan
</p>
</div>
<NewsShareItem item={item as any} isPage />
</div>
</div>
</section>
</article>
);
}
2 changes: 2 additions & 0 deletions src/lib/api/resource/items/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ export { default as organization_pejabat } from './organization_pejabat';
export { default as organizations } from './organizations';
export { default as public_services } from './public_services';
export { default as web_aduan_publik } from './web_aduan_publik';
export { default as web_menu } from './web_menu';
export { default as web_news } from './web_news';
export { default as web_pages } from './web_pages';
export { default as websites } from './websites';
50 changes: 50 additions & 0 deletions src/lib/api/resource/items/web_menu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import _ from 'lodash';
import { createApiResource } from '../base';

export default createApiResource('web_menu', {
baseFields: [
'id',
'slug',
'title',
'status',
'title',
'sort',
{ pages: ['id', 'title', 'status', 'slug', 'sort'] },
{ website: ['id', 'name', 'subdomain'] },
{
user_created: ['first_name', 'last_name', 'content_author_name'],
},
{ user_updated: ['first_name', 'last_name', 'content_author_name'] },
'date_updated',
'date_created',
],
baseQuery: {
sort: ['sort'],
filter: { status: { _eq: 'published' } },
},
baseNormalizer: (data) => {
return data;
},
}).addPath('read', 'siteMenu', (res) => async ({ paths: [websiteId] }) => {
if (!websiteId) res.errorThrow('Website dibutuhkan.');
return await res.read
.clientOptions({ cache: 'no-cache' })
.setQuery({
filter: { website: { _eq: websiteId } },
limit: -1,
})
.items({
normalizer: [
[
'id',
'title',
'slug',
'sort',
{ pages: ['id', 'slug', 'title', 'sort', 'description'] },
],
(data) => {
return data;
},
],
});
});
59 changes: 59 additions & 0 deletions src/lib/api/resource/items/web_pages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import _ from 'lodash';
import { createApiResource } from '../base';
import {
imageFileNormalizer,
contentBlocksNormalizer,
} from '../../normalizer-helper';

export default createApiResource('web_pages', {
baseFields: [
'id',
'slug',
'title',
'description',
'sort',
'menu',
{ image_cover: ['*'] },
{ website: ['id', 'name', 'subdomain'] },
{
user_created: ['first_name', 'last_name', 'content_author_name'],
},
{ user_updated: ['first_name', 'last_name', 'content_author_name'] },
'date_updated',
'date_created',
],
baseQuery: {
sort: ['sort'],
filter: { status: { _eq: 'published' } },
},
baseNormalizer: (data) => {
return {
..._.omit(data, 'user_updated', 'user_created'),
image_cover: data.image_cover
? imageFileNormalizer(data.image_cover!)
: null,
};
},
}).addPath('read', 'bySlug', (res) => ({ paths: [websiteId, slug] }) => {
if (!websiteId) res.errorThrow('Website dibutuhkan.');
if (!slug) res.errorThrow('Slug dibutuhkan.');
return res.read
.setQuery({
filter: {
website: { _eq: websiteId },
slug: { _eq: slug },
},
})
.items({
normalizer: [
[...res.baseFields, 'content'],
(data) => {
return {
...res.baseNormalizer(data),
content: contentBlocksNormalizer(data.content),
};
},
],
single: true,
});
});
27 changes: 27 additions & 0 deletions src/lib/data/site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BaseIconNamesType } from '@/components/icons/base-icon';
import { apiResourceItemPathRead } from '../server';
import { TWebsiteItemBySubdomain, TWebsiteMenu } from '@/types';
import { urlToWww } from '@/init';
import _ from 'lodash';

export async function dataSiteBySubdomain(subdomain: string) {
return await apiResourceItemPathRead('websites')
Expand All @@ -17,6 +18,12 @@ export async function dataSiteBeritaBySlug(slug: string) {
.catch(() => null);
}

export async function dataSitePageBySlug(websiteId: string, slug: string) {
return await apiResourceItemPathRead('web_pages')
.bySlug({ paths: [websiteId, slug] })
.catch(() => null);
}

export function dataSiteMenuProfilItems(
site: TWebsiteItemBySubdomain
): TWebsiteMenu['items'] {
Expand Down Expand Up @@ -110,6 +117,26 @@ export async function dataSiteMenu(site: TWebsiteItemBySubdomain) {
items: dataSiteMenuDokumenItems(site),
},
];
const menusData = await apiResourceItemPathRead('web_menu')
.siteMenu({ paths: [site.id] })
.catch((e) => null);

if (menusData) {
_.forEach(menusData, (menu) => {
menuItems.push({
title: menu.title,
link: `/menu/${menu.slug}`,
items: _.map(_.sortBy(menu.pages, 'sort'), (page) => {
return {
title: page.title,
link: `/page/${page.slug}`,
description: page.description ?? '',
icon: 'newspaper',
};
}),
});
});
}
if (modules.indexOf('aduan_publik') >= 0) {
menuItems.push({
title: 'Aduan Publik',
Expand Down
2 changes: 2 additions & 0 deletions src/types/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export type TApiResourcePathReturn<
export type TNewsItemBySlug = TApiResourcePathReturn<'news'>['read']['bySlug'];
export type TWebNewsItemBySlug =
TApiResourcePathReturn<'web_news'>['read']['bySlug'];
export type TWebPageItemBySlug =
TApiResourcePathReturn<'web_pages'>['read']['bySlug'];

export type TNewsOrWebNewsItemBySlug = TNewsItemBySlug | TWebNewsItemBySlug;

Expand Down
4 changes: 4 additions & 0 deletions src/types/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { PublicServices, PublicServicesMedia } from './public_services';
import { WebAduanPublik } from './web_aduan_publik';
import { WebNews } from './web_news';
import { Websites } from './websites';
import { WebPages } from './web_pages';
import { WebMenu } from './web_menu';

export * from './_base';

Expand All @@ -41,7 +43,9 @@ export type ApiItemsSchema = CompleteSchema<{
public_services_media: PublicServicesMedia[];
public_services: PublicServices[];
web_aduan_publik: WebAduanPublik[];
web_menu: WebMenu[];
web_news: WebNews[];
web_pages: WebPages[];
websites: Websites[];
directus_users: MergeCoreCollection<
CoreSchema,
Expand Down
18 changes: 18 additions & 0 deletions src/types/schemas/web_menu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { TDirectusStatusField, TDirectusUser } from './_base';
import { WebPages } from './web_pages';
import { Websites } from './websites';

export interface WebMenu {
id: string;
status: TDirectusStatusField;
title: string;
slug: string;
website: string | Websites;
sort: number;
pages: WebPages[];

user_created: string | TDirectusUser;
user_updated: string | TDirectusUser;
date_updated?: string;
date_created: string;
}
25 changes: 25 additions & 0 deletions src/types/schemas/web_pages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { TDirectusFile, TDirectusStatusField, TDirectusUser } from './_base';
import { WebMenu } from './web_menu';
import { Websites } from './websites';

export interface WebPages {
id: string;
status: TDirectusStatusField;
title: string;
slug: string;
description: null | string;
website: string | Websites;
image_cover: string | TDirectusFile;
menu: string | WebMenu;
sort: number;
content: {
time: number;
blocks: JSON;
version: string;
};

user_created: string | TDirectusUser;
user_updated: string | TDirectusUser;
date_updated?: string;
date_created: string;
}

0 comments on commit d27706c

Please sign in to comment.