Skip to content

Commit

Permalink
feat: add side nav api
Browse files Browse the repository at this point in the history
  • Loading branch information
limsohee1002 committed Nov 5, 2024
1 parent 03fd634 commit 2bf2b89
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 20 deletions.
37 changes: 23 additions & 14 deletions assets/shared-bundle.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions assets/tailwind-output.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default defineConfig([
'article-page': 'src/modules/article-page/index.ts',
'category-page': 'src/modules/category-page/index.ts',
'section-page': 'src/modules/section-page/index.ts',
'side-nav': 'src/modules/side-nav/index.ts',
},
output: {
dir: 'assets',
Expand Down
20 changes: 20 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,23 @@ export type CategoryPageData = {
export type SectionPageData = {
section: Section;
};

export type SideNavData = {
categories: {
id: number;
url: string;
name: string;
position: number;
sections: {
name: string;
id: number;
position: number;
url: string;
articles: {
name: string;
id: number;
url: string;
}[];
}[];
}[];
};
11 changes: 11 additions & 0 deletions src/modules/side-nav/SideNavModule.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { FC } from 'react';
import { SideNavData } from '../../lib/types';
import cn from 'classnames';

Check warning on line 3 in src/modules/side-nav/SideNavModule.tsx

View workflow job for this annotation

GitHub Actions / Lint JS files

'cn' is defined but never used

type Props = {
sideNavData: SideNavData;
};

export const SideNav: FC<Props> = ({ sideNavData }) => {

Check warning on line 9 in src/modules/side-nav/SideNavModule.tsx

View workflow job for this annotation

GitHub Actions / Lint JS files

'sideNavData' is defined but never used
return <div>Siiiide naaav</div>;
};
140 changes: 140 additions & 0 deletions src/modules/side-nav/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { SideNavData } from '../../lib/types';

const makeArrayToHaveUniqueValues = (array: { id: number }[]) => {
return array.filter((value, index, self) => self.findIndex((v) => v.id === value.id) === index);
};

type SideNavApiResponse = {
articles: {
section_id: number;
id: number;
url: string;
name: string;
position: number;
}[];
categories: {
id: number;
position: number;
url: string;
name: string;
}[];
sections: {
category_id: number;
id: number;
url: string;
name: string;
position: number;
}[];
};

const sanitizeResponse = (response: SideNavApiResponse): SideNavData => {
if (!response) {
return null;
}

if (!response.articles || !response.categories || !response.sections) {
return null;
}

const categories = response.categories.map((category) => {
const sections = response.sections
.filter((section) => section.category_id === category.id)
.map((section) => {
const articles = response.articles
.filter((article) => article.section_id === section.id)
.map((article) => ({
id: article.id,
name: article.name,
url: article.url,
position: article.position,
}));

return {
id: section.id,
name: section.name,
position: section.position,
url: section.url,
articles: articles.sort((a, b) => a.position - b.position),
};
});

return {
id: category.id,
name: category.name,
position: category.position,
url: category.url,
sections: sections.sort((a, b) => a.position - b.position),
};
});

return { categories: categories.sort((a, b) => a.position - b.position) };
};

export const sideNav = {
get: async (): Promise<SideNavData> => {
const url = `${window.location.origin}/api/v2/help_center/en-us/articles.json?include=categories,sections&per_page=100`;

try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Response status: ${response.status}`);
}

const responseData = await response.json();

if (responseData.page_count <= 1) {
return sanitizeResponse(responseData);
}

// fetch the rest of the pages since first page is already fetched above.
const pages = await Promise.all(
Array.from({ length: responseData.page_count - 1 }, (_, i) => {
return sideNav.getPage(i + 2);
})
);

const allPagesArticleResponseData = makeArrayToHaveUniqueValues(
responseData.articles.concat(
...pages.map((page: SideNavApiResponse | null) => page?.articles || [])
)
);
const allPagesSectionResponseData = makeArrayToHaveUniqueValues(
responseData.sections.concat(
...pages.map((page: SideNavApiResponse | null) => page?.sections || [])
)
);
const allPagesCategoryResponseData = makeArrayToHaveUniqueValues(
responseData.categories.concat(
...pages.map((page: SideNavApiResponse | null) => page?.categories || [])
)
);
const allPagesResponseData = {
...responseData,
articles: allPagesArticleResponseData,
sections: allPagesSectionResponseData,
categories: allPagesCategoryResponseData,
};
const sanitizedResponse = sanitizeResponse(allPagesResponseData);
console.log(sanitizedResponse);
return sanitizedResponse;
} catch (error) {
console.error(error);
return null;
}
},
getPage: async (page: number): Promise<SideNavApiResponse | null> => {
const url = `${window.location.origin}/api/v2/help_center/en-us/articles.json?include=categories,sections&page=${page}&per_page=100`;

try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Response status: ${response.status}`);
}

return await response.json();
} catch (error) {
console.error(error);
return null;
}
},
};
2 changes: 2 additions & 0 deletions src/modules/side-nav/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { renderSideNav } from './renderSideNav';
export { sideNav } from './api';
18 changes: 18 additions & 0 deletions src/modules/side-nav/renderSideNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { render } from 'react-dom';
import { SideNavData } from '../../lib/types';
import { Settings } from '../shared';
import { createTheme, ThemeProviders } from '../shared';
import { SideNav } from './SideNavModule';

export async function renderSideNav(
settings: Settings,
sideNavData: SideNavData,
container: HTMLElement
) {
render(
<ThemeProviders theme={createTheme(settings)}>
<SideNav sideNavData={sideNavData} />
</ThemeProviders>,
container
);
}
1 change: 1 addition & 0 deletions templates/document_head.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"article-page": "{{asset 'article-page-bundle.js'}}",
"category-page": "{{asset 'category-page-bundle.js'}}",
"section-page": "{{asset 'section-page-bundle.js'}}",
"side-nav": "{{asset 'side-nav-bundle.js'}}",
"new-request-form-translations": "{{asset 'new-request-form-translations-bundle.js'}}",
"shared": "{{asset 'shared-bundle.js'}}",
"wysiwyg": "{{asset 'wysiwyg-bundle.js'}}",
Expand Down
19 changes: 17 additions & 2 deletions templates/home_page.hbs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="Homepage flex flex-row bg-light-surface-1 dark:bg-dark-surface-1">
<div class="min-w-[15rem] max-w-[15rem] hidden md:block border-2 mt-nav-h">sidenav placeholder</div>
<div id="new-side-nav" class="min-w-[15rem] max-w-[15rem] hidden md:block border-2 mt-nav-h">sidenav placeholder</div>
<div id="new-homepage"></div>
</div>

Expand All @@ -9,7 +9,6 @@
const container = document.getElementById("new-homepage");
const settings = {{json settings}};
// Handles data for the homepage. If you would like to update any data within homepage, adjust it here.
const homepageData = {
heros: [{
Expand Down Expand Up @@ -109,4 +108,20 @@
// Make sure arguments are correctly typed.
renderHomepage(settings, homepageData, container);
</script>


<script type="module">
import { renderSideNav, sideNav } from "side-nav";
const container = document.getElementById("new-side-nav");
const settings = {{json settings}};
const sideNavData = await sideNav.get();
// Make sure arguments are correctly typed.
renderSideNav(settings, sideNavData, container);
</script>

0 comments on commit 2bf2b89

Please sign in to comment.