Skip to content

Commit

Permalink
refactor: serverErrorboundary를 hoc로 refactoring 및 ui 패키지로 이동 (#192)
Browse files Browse the repository at this point in the history
  • Loading branch information
saseungmin authored Sep 17, 2024
1 parent cfd0963 commit 856578b
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 131 deletions.
44 changes: 22 additions & 22 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,6 @@ jobs:
path: ${{ needs.job_install_dependencies.outputs.yarn_cache_dir_path }}
key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }}

- name: Compute @dnd-academy/ui cache key
id: compute_ui_cache_key
run: echo "hash=${{ runner.os }}-ui-build-${{ hashFiles('packages/ui/**') }}" >> $GITHUB_OUTPUT

- name: Check @dnd-academy/ui build cache
uses: actions/cache@v4
id: cache_built_ui_packages
with:
path: ${{ env.CACHED_BUILD_PACKAGE_UI_PATHS }}
key: ${{ steps.compute_ui_cache_key.outputs.hash }}

- name: Build @dnd-academy/ui
if: steps.cache_built_ui_packages.outputs.cache-hit != 'true'
run: yarn workspace @dnd-academy/ui build

- name: Compute @dnd-academy/core cache key
id: compute_core_cache_key
run: echo "hash=${{ runner.os }}-core-build-${{ hashFiles('packages/core/**') }}" >> $GITHUB_OUTPUT
Expand All @@ -111,11 +96,26 @@ jobs:
if: steps.cache_built_core_packages.outputs.cache-hit != 'true'
run: yarn workspace @dnd-academy/core build

- name: Compute @dnd-academy/ui cache key
id: compute_ui_cache_key
run: echo "hash=${{ runner.os }}-ui-build-${{ hashFiles('packages/ui/**') }}" >> $GITHUB_OUTPUT

- name: Check @dnd-academy/ui build cache
uses: actions/cache@v4
id: cache_built_ui_packages
with:
path: ${{ env.CACHED_BUILD_PACKAGE_UI_PATHS }}
key: ${{ steps.compute_ui_cache_key.outputs.hash }}

- name: Build @dnd-academy/ui
if: steps.cache_built_ui_packages.outputs.cache-hit != 'true'
run: yarn workspace @dnd-academy/ui build

outputs:
dependency_cache_key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }}
yarn_cache_dir_path: ${{ needs.job_install_dependencies.outputs.yarn_cache_dir_path }}
build_package_ui_cache_key: ${{ steps.compute_ui_cache_key.outputs.hash }}
build_package_core_cache_key: ${{ steps.compute_core_cache_key.outputs.hash }}
build_package_ui_cache_key: ${{ steps.compute_ui_cache_key.outputs.hash }}

# continuous-integration:
# needs: [job_packages_build]
Expand Down Expand Up @@ -168,18 +168,18 @@ jobs:
path: ${{ needs.job_packages_build.outputs.yarn_cache_dir_path }}
key: ${{ needs.job_packages_build.outputs.dependency_cache_key }}

- name: Check build ui package cache
uses: actions/cache@v4
with:
path: ${{ env.CACHED_BUILD_PACKAGE_UI_PATHS }}
key: ${{ needs.job_packages_build.outputs.build_package_ui_cache_key }}

- name: Check build core package cache
uses: actions/cache@v4
with:
path: ${{ env.CACHED_BUILD_PACKAGE_CORE_PATHS }}
key: ${{ needs.job_packages_build.outputs.build_package_core_cache_key }}

- name: Check build ui package cache
uses: actions/cache@v4
with:
path: ${{ env.CACHED_BUILD_PACKAGE_UI_PATHS }}
key: ${{ needs.job_packages_build.outputs.build_package_ui_cache_key }}

- name: Publish Project to Chromatic
uses: chromaui/action@latest
with:
Expand Down
52 changes: 26 additions & 26 deletions apps/admin/src/app/current-applicant-count/page.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
import { CurrentApplicantCount } from '@dnd-academy/core';
import { Counter, PageTitle } from '@dnd-academy/ui';
import { withServerErrorBoundary } from '@dnd-academy/ui/server';

import ServerErrorBoundary from '@/components/common/ServerErrorBoundary';
import CurrentApplicantCountAction from '@/components/CurrentApplicantCountAction';

import styles from './page.module.scss';

async function page() {
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
type Props = {
data: CurrentApplicantCount;
};

async function Page({ data }: Props) {
const { designer, developer } = data;

return (
<ServerErrorBoundary<CurrentApplicantCount> apiRequest={{
url: `${protocol}://${process.env.VERCEL_URL}/api/blob/latest/current_applicant_count`,
}}
>
{({ designer, developer }) => (
<>
<PageTitle
title="현재 지원자 수"
subTitle="현재 지원자 수는 google form의 spreadsheet를 통해 실시간으로 업데이트 됩니다."
/>
<div className={styles.counter}>
오늘까지&nbsp;
<Counter count={designer + developer} />
명이 지원했어요!
</div>
<CurrentApplicantCountAction />
<strong>
기본적으로 매일 00:00에 자동으로 반영되지만, 클릭시에는 즉시 반영할 수 있습니다.
</strong>
</>
)}
</ServerErrorBoundary>
<>
<PageTitle
title="현재 지원자 수"
subTitle="현재 지원자 수는 google form의 spreadsheet를 통해 실시간으로 업데이트 됩니다."
/>
<div className={styles.counter}>
오늘까지&nbsp;
<Counter count={designer + developer} />
명이 지원했어요!
</div>
<CurrentApplicantCountAction />
<strong>
기본적으로 매일 00:00에 자동으로 반영되지만, 클릭시에는 즉시 반영할 수 있습니다.
</strong>
</>
);
}

export default page;
export default withServerErrorBoundary(Page, {
url: '/blob/latest/current_applicant_count',
type: 'bff',
});
56 changes: 28 additions & 28 deletions apps/admin/src/app/total-count-status/page.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
import { type TotalCountStatus } from '@dnd-academy/core';
import { CounterCard, PageTitle } from '@dnd-academy/ui';
import { withServerErrorBoundary } from '@dnd-academy/ui/server';

import ServerErrorBoundary from '@/components/common/ServerErrorBoundary';
import TotalCountStatusForm from '@/components/TotalCountStatusForm';

import styles from './page.module.scss';

async function page() {
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
type Props = {
data: TotalCountStatus;
};

async function Page({ data }: Props) {
const {
cumulativeApplicants, dropouts, totalParticipants, totalProjects,
} = data;

return (
<ServerErrorBoundary<TotalCountStatus> apiRequest={{
url: `${protocol}://${process.env.VERCEL_URL}/blob/latest/total_count_status`,
}}
>
{({
<>
<PageTitle
title="지원자 수 카드 섹션"
subTitle="캐시 적용으로 실제 적용까지는 최대 5분정도 소요됩니다."
/>
<div className={styles.counterCardWrapper}>
<CounterCard count={cumulativeApplicants} title="누적 지원자 수" />
<CounterCard count={totalParticipants} title="총 참가자 수" />
<CounterCard count={totalProjects} title="총 프로젝트 수" suffix="개" />
<CounterCard count={dropouts} title="이탈자 수" color="primary" />
</div>
<TotalCountStatusForm initialTotalCountStatus={{
cumulativeApplicants, totalParticipants, totalProjects, dropouts,
}) => (
<>
<PageTitle
title="지원자 수 카드 섹션"
subTitle="캐시 적용으로 실제 적용까지는 최대 5분정도 소요됩니다."
/>
<div className={styles.counterCardWrapper}>
<CounterCard count={cumulativeApplicants} title="누적 지원자 수" />
<CounterCard count={totalParticipants} title="총 참가자 수" />
<CounterCard count={totalProjects} title="총 프로젝트 수" suffix="개" />
<CounterCard count={dropouts} title="이탈자 수" color="primary" />
</div>
<TotalCountStatusForm initialTotalCountStatus={{
cumulativeApplicants, totalParticipants, totalProjects, dropouts,
}}
/>
</>
)}
</ServerErrorBoundary>
}}
/>
</>
);
}

export default page;
export default withServerErrorBoundary(Page, {
url: '/blob/latest/total_count_status',
type: 'bff',
});
45 changes: 0 additions & 45 deletions apps/admin/src/components/common/ServerErrorBoundary/index.tsx

This file was deleted.

10 changes: 0 additions & 10 deletions apps/admin/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,3 @@ export function isEmailAllowed(email: string) {

return allowedEmails.includes(email);
}

export const serverErrorHandling = async <T>(apiCallback: () => Promise<T>) => {
try {
const response = await apiCallback();

return response;
} catch (error) {
return null;
}
};
10 changes: 10 additions & 0 deletions packages/core/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,13 @@ export const getLatestItemReduce = (
items: ListBlobResultBlob[],
): ListBlobResultBlob => items
.reduce((latest, current) => (current.uploadedAt > latest.uploadedAt ? current : latest));

export const serverErrorHandling = async <T>(apiCallback: () => Promise<T>) => {
try {
const response = await apiCallback();

return response;
} catch (error) {
return null;
}
};
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
"vite-plugin-svgr": "4.2.0"
},
"dependencies": {
"@dnd-academy/core": "*",
"clsx": "2.1.1",
"framer-motion": "11.2.10",
"next": "14.2.4",
Expand Down
50 changes: 50 additions & 0 deletions packages/ui/src/hoc/withServerErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ComponentType, ReactNode } from 'react';

import { api, type ApiRequest, serverErrorHandling } from '@dnd-academy/core';

function withServerErrorBoundary<T, P extends object | undefined>(
WrappedComponent: ComponentType<P & { data: T }>,
apiRequest: ApiRequest<T>,
) {
return function WithServerErrorBoundary(props: Omit<P, 'data'>): JSX.Element {
const data = serverErrorHandling(() => api(apiRequest));

return (
<>
{/* @ts-expect-error Server Component */}
<AsyncRenderer
data={data}
fallback={<div>Failed to fetch data</div>}
>
{(resolvedData) => (
<WrappedComponent
// eslint-disable-next-line react/jsx-props-no-spreading
{...(props as P)}
data={resolvedData as T}
/>
)}
</AsyncRenderer>
</>
);
};
}

async function AsyncRenderer<T>({
data,
children,
fallback,
}: {
data: Promise<T>;
children: (data: T) => ReactNode;
fallback: ReactNode;
}) {
const resolvedData = await data;

if (!resolvedData) {
return fallback;
}

return children(resolvedData);
}

export default withServerErrorBoundary;
1 change: 1 addition & 0 deletions packages/ui/src/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as withServerErrorBoundary } from './hoc/withServerErrorBoundary';
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1993,6 +1993,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@dnd-academy/ui@workspace:packages/ui"
dependencies:
"@dnd-academy/core": "npm:*"
"@dnd-academy/eslint-config": "npm:*"
"@storybook/blocks": "npm:8.2.1"
"@storybook/react": "npm:8.2.1"
Expand Down

0 comments on commit 856578b

Please sign in to comment.