diff --git a/src-ts/.eslintrc.js b/src-ts/.eslintrc.js index d80fc63f5..2e5fbbbed 100644 --- a/src-ts/.eslintrc.js +++ b/src-ts/.eslintrc.js @@ -44,7 +44,12 @@ module.exports = { } } ], - '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-function-return-type': [ + 'error', + { + allowExpressions: true + } + ], '@typescript-eslint/no-explicit-any': 'error', '@typescript-eslint/no-inferrable-types': 'off', '@typescript-eslint/no-shadow': 'error', @@ -59,6 +64,19 @@ module.exports = { allowNullableString: true } ], + '@typescript-eslint/typedef': [ + 'error', + { + arrowParameter: false, + propertyDeclaration: true, + parameter: true, + memberVariableDeclaration: true, + callSignature: true, + variableDeclaration: true, + arrayDestructuring: false, + objectDestructuring: true + } + ], 'arrow-parens': [ 'error', 'as-needed' @@ -171,13 +189,41 @@ module.exports = { 'padded-blocks': 'off', 'padding-line-between-statements': [ 'error', - { blankLine: 'always', prev: 'directive', next: '*' }, - { blankLine: 'any', prev: 'directive', next: 'directive' }, - { blankLine: 'always', prev: 'cjs-import', next: '*' }, - { blankLine: 'any', prev: 'cjs-import', next: 'cjs-import' }, - { blankLine: 'always', prev: 'cjs-export', next: '*' }, - { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, - { blankLine: 'always', prev: 'class', next: '*' } + { + blankLine: 'always', + prev: 'directive', + next: '*' + }, + { + blankLine: 'any', + prev: 'directive', + next: 'directive' + }, + { + blankLine: 'always', + prev: 'cjs-import', + next: '*' + }, + { + blankLine: 'any', + prev: 'cjs-import', + next: 'cjs-import' + }, + { + blankLine: 'always', + prev: 'cjs-export', + next: '*' + }, + { + blankLine: 'always', + prev: 'multiline-block-like', + next: '*' + }, + { + blankLine: 'always', + prev: 'class', + next: '*' + } ], 'prefer-destructuring': 'off', 'react-hooks/exhaustive-deps': 'warn', @@ -187,9 +233,10 @@ module.exports = { 'never' ], 'react/function-component-definition': [ - 2, + 'error', { - namedComponents: 'arrow-function' + namedComponents: 'arrow-function', + unnamedComponents: 'function-expression' } ], 'react/jsx-filename-extension': [ diff --git a/src-ts/lib/route-provider/require-auth-provider/require-auth.provider.tsx b/src-ts/lib/route-provider/require-auth-provider/require-auth.provider.tsx index c69d86632..80c3dddb4 100644 --- a/src-ts/lib/route-provider/require-auth-provider/require-auth.provider.tsx +++ b/src-ts/lib/route-provider/require-auth-provider/require-auth.provider.tsx @@ -9,39 +9,40 @@ interface RequireAuthProviderProps { rolesRequired?: Array } -const RequireAuthProvider = (props: RequireAuthProviderProps): JSX.Element => { +const RequireAuthProvider: (props: RequireAuthProviderProps) => JSX.Element + = (props: RequireAuthProviderProps): JSX.Element => { - const profileContextData: ProfileContextData = useContext(profileContext) - const { profile, initialized }: ProfileContextData = profileContextData + const profileContextData: ProfileContextData = useContext(profileContext) + const { profile, initialized }: ProfileContextData = profileContextData - // if we're not initialized yet, just return the children - if (!initialized) { - return props.children - } + // if we're not initialized yet, just return the children + if (!initialized) { + return props.children + } - // if we have a profile and `rolesRequired` is configured for the route - // check the user's roles, allow access or show restricted page - if (!!profile) { - if (props.rolesRequired) { - if (!profile.roles) { - return RestrictedPage - } + // if we have a profile and `rolesRequired` is configured for the route + // check the user's roles, allow access or show restricted page + if (!!profile) { + if (props.rolesRequired) { + if (!profile.roles) { + return RestrictedPage + } + + // if the profile doesn't include all the required roles, show the restricted page + if (props.rolesRequired.some(role => !profile.roles.includes(role))) { + return RestrictedPage + } - // if the profile doesn't include all the required roles, show the restricted page - if (props.rolesRequired.some(role => !profile.roles.includes(role))) { - return RestrictedPage + return props.children } return props.children - } - return props.children + } + // redirect to the login page + window.location.href = props.loginUrl + return <> } - // redirect to the login page - window.location.href = props.loginUrl - return <> -} - export default RequireAuthProvider diff --git a/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/MarkdownCode.tsx b/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/MarkdownCode.tsx index 27be3abb4..b92fe9028 100644 --- a/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/MarkdownCode.tsx +++ b/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/MarkdownCode.tsx @@ -32,9 +32,7 @@ export const MarkdownCode: React.FC = props => { return (
{ - const { codeRef, showLineNumbers, onVisibilityChange }: LineNumbersProps - = props - const [lineNumbers, setLineNumbers]: [ - Array, - React.Dispatch>> - ] = React.useState([1]) - - const size: ReturnType = useWindowSize() - - // OnResizing - const debounceTimer: React.MutableRefObject< - ReturnType | undefined - > = React.useRef>() - React.useEffect(() => { - if (!size.width || !codeRef.current) { - return - } +const LineNumbers: (props: LineNumbersProps) => React.ReactElement | null + = (props: LineNumbersProps): React.ReactElement | null => { + + const { codeRef, showLineNumbers, onVisibilityChange }: LineNumbersProps + = props + const [lineNumbers, setLineNumbers]: [ + Array, + React.Dispatch>> + ] = React.useState([1]) + + const size: ReturnType = useWindowSize() + + // OnResizing + const debounceTimer: React.MutableRefObject< + ReturnType | undefined + > = React.useRef>() + React.useEffect(() => { + if (!size.width || !codeRef.current) { + return + } - if (debounceTimer.current) { - clearTimeout(debounceTimer.current) - debounceTimer.current = undefined - } + if (debounceTimer.current) { + clearTimeout(debounceTimer.current) + debounceTimer.current = undefined + } - const pre: HTMLPreElement | null = codeRef.current.querySelector('pre') - if (!pre) { - return - } + const pre: HTMLPreElement | null = codeRef.current.querySelector('pre') + if (!pre) { + return + } + + const innerText: string = pre.innerText + const clientWidth: number = pre.clientWidth - const innerText: string = pre.innerText - const clientWidth: number = pre.clientWidth + const handleResizing: () => void = () => { + const result: Array = computeLineNumbers( + innerText, + clientWidth, + ) - const handleResizing: () => void = () => { - const result: Array = computeLineNumbers( - innerText, - clientWidth, - ) + if (result.length < 2) { + onVisibilityChange(false) + } else { + onVisibilityChange(true) + } - if (result.length < 2) { - onVisibilityChange(false) - } else { - onVisibilityChange(true) + setLineNumbers(result) } - setLineNumbers(result) - } + debounceTimer.current = setTimeout(() => { + debounceTimer.current = undefined + handleResizing() + }, 100) - debounceTimer.current = setTimeout(() => { - debounceTimer.current = undefined - handleResizing() - }, 100) + return () => { + clearTimeout(debounceTimer.current) + } + }, [size.width, onVisibilityChange, codeRef]) - return () => { - clearTimeout(debounceTimer.current) + if (!showLineNumbers) { + return null } - }, [size.width, onVisibilityChange, codeRef]) - if (!showLineNumbers) { - return null + return ( +
+ {lineNumbers.map((n, index) => { + const prev: number = index > 0 ? lineNumbers[index - 1] : -1 + return ( +
+ {n} +
+ ) + })} +
+ ) } - return ( -
- {lineNumbers.map((n, index) => { - const prev: number = index > 0 ? lineNumbers[index - 1] : -1 - return ( -
- {n} -
- ) - })} -
- ) -} - function measureText(text: string, canvas: HTMLCanvasElement): number { const context: CanvasRenderingContext2D | null = canvas.getContext('2d') if (!context) { diff --git a/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-action-renderer/MemberActionRenderer.tsx b/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-action-renderer/MemberActionRenderer.tsx index 7ad6a4543..35af4964e 100644 --- a/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-action-renderer/MemberActionRenderer.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-action-renderer/MemberActionRenderer.tsx @@ -1,33 +1,35 @@ +/* eslint-disable arrow-body-style */ // TODO: enable when unassign feature is ready // import { Button, ButtonProps, useCheckIsMobile } from '../../../../../../../lib' import { MemberBadgeAward } from '../../../../../game-lib' import styles from './MemberActionRenderer.module.scss' -const MemberActionRenderer = (memberAward: MemberBadgeAward): JSX.Element => +const MemberActionRenderer: (memberAward: MemberBadgeAward) => JSX.Element + = (memberAward: MemberBadgeAward): JSX.Element => { -// const isMobile: boolean = useCheckIsMobile() + // const isMobile: boolean = useCheckIsMobile() -// const buttonProps: ButtonProps = { -// buttonStyle: 'secondary', -// size: isMobile ? 'xs' : 'sm', -// } + // const buttonProps: ButtonProps = { + // buttonStyle: 'secondary', + // size: isMobile ? 'xs' : 'sm', + // } -// const actionButtons: Array<{ -// label: string -// }> = [ -// { -// label: 'Unassign', -// }, -// ] + // const actionButtons: Array<{ + // label: string + // }> = [ + // { + // label: 'Unassign', + // }, + // ] -// function onUnassign(): void { + // function onUnassign(): void { -// } + // } - ( -
- {/* {actionButtons.map((button, index) => { + return ( +
+ {/* {actionButtons.map((button, index) => { return (
- ) +
+ ) + } export default MemberActionRenderer diff --git a/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-awardedAt-renderer/MemberAwaredAtRenderer.tsx b/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-awardedAt-renderer/MemberAwaredAtRenderer.tsx index 7d80d3cf8..07fde8a8b 100644 --- a/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-awardedAt-renderer/MemberAwaredAtRenderer.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-awardedAt-renderer/MemberAwaredAtRenderer.tsx @@ -2,21 +2,23 @@ import { MemberBadgeAward } from '../../../../../game-lib' import styles from './MemberAwaredAtRenderer.module.scss' -const MemberAwaredAtRenderer = (memberAward: MemberBadgeAward): JSX.Element => { - const dateFormat: Record = { - day: 'numeric', - hour: 'numeric', - minute: 'numeric', - month: 'short', - year: 'numeric', - } +const MemberAwaredAtRenderer: (memberAward: MemberBadgeAward) => JSX.Element + = (memberAward: MemberBadgeAward): JSX.Element => { + + const dateFormat: Record = { + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + month: 'short', + year: 'numeric', + } - return ( -
- {new Date(memberAward.awarded_at) - .toLocaleString(undefined, dateFormat)} -
- ) -} + return ( +
+ {new Date(memberAward.awarded_at) + .toLocaleString(undefined, dateFormat)} +
+ ) + } export default MemberAwaredAtRenderer diff --git a/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-handle-renderer/MemberHandleRenderer.tsx b/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-handle-renderer/MemberHandleRenderer.tsx index 1c47b2788..b684ddaab 100644 --- a/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-handle-renderer/MemberHandleRenderer.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-handle-renderer/MemberHandleRenderer.tsx @@ -4,14 +4,15 @@ import { MemberBadgeAward } from '../../../../../game-lib' import styles from './MemberHandleRenderer.module.scss' -const MemberHandleRenderer = (memberAward: MemberBadgeAward): JSX.Element => ( -
-

{memberAward.user_handle}

- window.open(`${EnvironmentConfig.TOPCODER_URLS.USER_PROFILE}/${memberAward.user_handle}`, '_blank')} - /> -
-) +const MemberHandleRenderer: (memberAward: MemberBadgeAward) => JSX.Element + = (memberAward: MemberBadgeAward): JSX.Element => ( +
+

{memberAward.user_handle}

+ window.open(`${EnvironmentConfig.TOPCODER_URLS.USER_PROFILE}/${memberAward.user_handle}`, '_blank')} + /> +
+ ) export default MemberHandleRenderer diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx index 2ae3076dd..82ab2ae4f 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx @@ -4,40 +4,42 @@ import { badgeDetailPath } from '../../../../gamification-admin.routes' import styles from './BadgeActionRenderer.module.scss' -const BadgeActionRenderer = (badge: GameBadge): JSX.Element => { +const BadgeActionRenderer: (badge: GameBadge) => JSX.Element + = (badge: GameBadge): JSX.Element => { - const isMobile: boolean = useCheckIsMobile() + const isMobile: boolean = useCheckIsMobile() - const buttonProps: ButtonProps = { - buttonStyle: 'secondary', - size: isMobile ? 'xs' : 'sm', - } + const buttonProps: ButtonProps = { + buttonStyle: 'secondary', + size: isMobile ? 'xs' : 'sm', + } - const actionButtons: Array<{ - label: string - view?: 'edit' | 'award' - }> = [ - { - label: 'View', - }, - { - label: 'Award', - view: 'award', - }, - ] + const actionButtons: Array<{ + label: string + view?: 'edit' | 'award' + }> + = [ + { + label: 'View', + }, + { + label: 'Award', + view: 'award', + }, + ] - return ( -
- {actionButtons.map((button, index) => ( -
- ) -} + return ( +
+ {actionButtons.map((button, index) => ( +
+ ) + } export default BadgeActionRenderer diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx index 09aef78dc..cc1e4f791 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx @@ -2,15 +2,16 @@ import { GameBadge } from '../../../../game-lib' import styles from './BadgeListingNameRenderer.module.scss' -const BadgeListingNameRenderer = (badge: GameBadge): JSX.Element => ( -
- {badge.badge_name} -

{badge.badge_name}

-
-) +const BadgeListingNameRenderer: (badge: GameBadge) => JSX.Element + = (badge: GameBadge): JSX.Element => ( +
+ {badge.badge_name} +

{badge.badge_name}

+
+ ) export default BadgeListingNameRenderer diff --git a/src-ts/tools/learn/welcome/WelcomePage.tsx b/src-ts/tools/learn/welcome/WelcomePage.tsx index 7f9b304a2..f594a75c7 100644 --- a/src-ts/tools/learn/welcome/WelcomePage.tsx +++ b/src-ts/tools/learn/welcome/WelcomePage.tsx @@ -16,7 +16,7 @@ import { ProgressBlock } from './progress-block' import { ReactComponent as TcAcademyFullLogoSvg } from './tca-full-logo.svg' import styles from './WelcomePage.module.scss' -const WelcomePage: FC<{}> = () => { +const WelcomePage: FC = () => { const allCertsData: AllCertificationsProviderData = useGetAllCertifications() const userCertsData: UserCertificationsProviderData = useGetUserCertifications() diff --git a/src-ts/tools/work/work-lib/work-status-item/WorkStatusItem.tsx b/src-ts/tools/work/work-lib/work-status-item/WorkStatusItem.tsx index f6e25a2ed..5fde3dbd4 100644 --- a/src-ts/tools/work/work-lib/work-status-item/WorkStatusItem.tsx +++ b/src-ts/tools/work/work-lib/work-status-item/WorkStatusItem.tsx @@ -6,24 +6,25 @@ export interface WorkStatusItemProps { workStatus?: WorkStatus } -const WorkStatusItem = ({ workStatus }: WorkStatusItemProps): JSX.Element => { +const WorkStatusItem: (props: WorkStatusItemProps) => JSX.Element + = (props: WorkStatusItemProps): JSX.Element => { - if (!workStatus) { - return <> - } + if (!props.workStatus) { + return <> + } - const statusKey: (keyof typeof WorkStatus) | undefined = Object.entries(WorkStatus) - .find(([key, value]) => value === workStatus) - ?.[0] as keyof typeof WorkStatus + const statusKey: (keyof typeof WorkStatus) | undefined = Object.entries(WorkStatus) + .find(([key, value]) => value === props.workStatus) + ?.[0] as keyof typeof WorkStatus - return ( -
-
-
- {workStatus} + return ( +
+
+
+ {props.workStatus} +
-
- ) -} + ) + } export default WorkStatusItem diff --git a/src-ts/tools/work/work-table/work-badge-renderer/WorkBadgeRenderer.tsx b/src-ts/tools/work/work-table/work-badge-renderer/WorkBadgeRenderer.tsx index 6a82d1ad8..4f0d1096c 100644 --- a/src-ts/tools/work/work-table/work-badge-renderer/WorkBadgeRenderer.tsx +++ b/src-ts/tools/work/work-table/work-badge-renderer/WorkBadgeRenderer.tsx @@ -8,25 +8,26 @@ interface WorkBadgeRendererProps { type: 'messages' | 'items' } -const WorkBadgeRenderer = (props: WorkBadgeRendererProps): JSX.Element => { +const WorkBadgeRenderer: (props: WorkBadgeRendererProps) => JSX.Element + = (props: WorkBadgeRendererProps): JSX.Element => { - if (props.count === undefined || (!!props.hideZero && props.count === 0)) { - return <> - } + if (props.count === undefined || (!!props.hideZero && props.count === 0)) { + return <> + } - const badgeColor: 'unread-messages' | 'no-unread-messages' | 'items' = props.type === 'items' - ? 'items' - : (props.count === 0 - ? 'no-unread-messages' - : 'unread-messages') + const badgeColor: 'unread-messages' | 'no-unread-messages' | 'items' = props.type === 'items' + ? 'items' + : (props.count === 0 + ? 'no-unread-messages' + : 'unread-messages') - return ( -
-
- {props.count} + return ( +
+
+ {props.count} +
-
- ) -} + ) + } export default WorkBadgeRenderer diff --git a/src-ts/tools/work/work-table/work-delete-button-renderer/WorkDeleteButtonRenderer.tsx b/src-ts/tools/work/work-table/work-delete-button-renderer/WorkDeleteButtonRenderer.tsx index 53bd78bc2..90a022579 100644 --- a/src-ts/tools/work/work-table/work-delete-button-renderer/WorkDeleteButtonRenderer.tsx +++ b/src-ts/tools/work/work-table/work-delete-button-renderer/WorkDeleteButtonRenderer.tsx @@ -10,54 +10,56 @@ import { import { Work, workContext, WorkContextData, workDeleteAsync, WorkStatus } from '../../work-lib' import '../../../../lib/styles/index.scss' -const WorkDeleteButtonRenderer = (work: Work): JSX.Element | undefined => { +const WorkDeleteButtonRenderer: (work: Work) => JSX.Element | undefined + = (work: Work): JSX.Element | undefined => { - const workContextData: WorkContextData = useContext(workContext) - const [confirmationOpen, setConfirmationOpen]: [boolean, Dispatch>] = useState(false) + const workContextData: WorkContextData = useContext(workContext) + const [confirmationOpen, setConfirmationOpen]: [boolean, Dispatch>] + = useState(false) - // if the item is in draft status, don't display anything - if (work.status !== WorkStatus.draft) { - return undefined - } + // if the item is in draft status, don't display anything + if (work.status !== WorkStatus.draft) { + return undefined + } - async function deleteWork(): Promise { - toggleConfirmation() - await workDeleteAsync(work.id) - await workContextData.remove(work.id, workContextData.work) - toast.success('Your draft work has been deleted.') - } + async function deleteWork(): Promise { + toggleConfirmation() + await workDeleteAsync(work.id) + await workContextData.remove(work.id, workContextData.work) + toast.success('Your draft work has been deleted.') + } - function toggleConfirmation(): void { - setConfirmationOpen(!confirmationOpen) - } + function toggleConfirmation(): void { + setConfirmationOpen(!confirmationOpen) + } - return ( - <> - - )} - /> - - - Are you sure you would like to delete your draft work? - This action can not be undone and will permanently remove your work. - - - ) -} + return ( + <> + + )} + /> + + + Are you sure you would like to delete your draft work? + This action can not be undone and will permanently remove your work. + + + ) + } export default WorkDeleteButtonRenderer diff --git a/src-ts/tools/work/work-table/work-status-renderer/WorkStatusRenderer.tsx b/src-ts/tools/work/work-table/work-status-renderer/WorkStatusRenderer.tsx index da8735408..3e7ccfd94 100644 --- a/src-ts/tools/work/work-table/work-status-renderer/WorkStatusRenderer.tsx +++ b/src-ts/tools/work/work-table/work-status-renderer/WorkStatusRenderer.tsx @@ -1,7 +1,6 @@ import { Work, WorkStatusItem } from '../../work-lib' -const WorkStatusRenderer = (work: Work): JSX.Element => ( - -) +const WorkStatusRenderer: (work: Work) => JSX.Element + = (work: Work): JSX.Element => export default WorkStatusRenderer diff --git a/src-ts/tools/work/work-table/work-table-title-renderer/WorkTableTitleRenderer.tsx b/src-ts/tools/work/work-table/work-table-title-renderer/WorkTableTitleRenderer.tsx index 5cce28a3a..e379caa46 100644 --- a/src-ts/tools/work/work-table/work-table-title-renderer/WorkTableTitleRenderer.tsx +++ b/src-ts/tools/work/work-table/work-table-title-renderer/WorkTableTitleRenderer.tsx @@ -9,47 +9,48 @@ import { import styles from './WorkTableTitleRenderer.module.scss' -const WorkTableTitleRenderer = (data: Work): JSX.Element => { - - let Icon: JSX.Element - switch (data.typeCategory) { - - case WorkTypeCategory.data: - Icon = - break - - case WorkTypeCategory.design: - Icon = - break - - case WorkTypeCategory.qa: - Icon = ( - } - /> - ) - break - - // TODO: dev work categories - default: - Icon = - break - } - - return ( -
- {Icon} -
-
- {data.title} -
-
- {data.description} +const WorkTableTitleRenderer: (data: Work) => JSX.Element + = (data: Work): JSX.Element => { + + let Icon: JSX.Element + switch (data.typeCategory) { + + case WorkTypeCategory.data: + Icon = + break + + case WorkTypeCategory.design: + Icon = + break + + case WorkTypeCategory.qa: + Icon = ( + } + /> + ) + break + + // TODO: dev work categories + default: + Icon = + break + } + + return ( +
+ {Icon} +
+
+ {data.title} +
+
+ {data.description} +
-
- ) -} + ) + } export default WorkTableTitleRenderer