Last active
June 29, 2024 16:03
-
-
Save pabletecodes/d7f1df2c4ff2beeb06ddab238dd203fd to your computer and use it in GitHub Desktop.
Design Challenge 003: Generating Context Menu from Legacy API Response
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Your challenge is to find ways to simplify this code further. | |
// You can use any patterns or refactoring techniques you find useful. | |
// Think about improving readability and maintainability while ensuring the | |
// functionality remains intact. | |
// Backend response | |
{ | |
"operations": [ | |
{ | |
"internal_legacy_field": "assign-issue", | |
"name": "Assign", | |
"desc": "Assign this issue to someone", | |
"url": "/issues/assign" | |
}, | |
{ | |
"internal_legacy_field": "assign-to-me", | |
"name": "Assign to me", | |
"desc": "Assign this issue to me", | |
"url": "/issues/assign-to-me/very/old/outdated/link" | |
}, | |
{ | |
"internal_legacy_field": "comment-issue", | |
"name": "Comment", | |
"desc": "Comment on this issue", | |
"url": "/comment/issue" | |
}, | |
{ | |
"internal_legacy_field": "log-work", | |
"name": "Log work", | |
"desc": "Log work against this issue" | |
} | |
] | |
} | |
// Code | |
const URL_OVERRIDE_FIELDS: Record<string, string> = { | |
"comment-issue": "/issues/comment", | |
}; | |
// There are more in the real product | |
const SKIP_FIELDS: string[] = ["log-work"]; | |
const DIALOG_FIELDS: string[] = ["assign-issue", "comment-issue"]; | |
const IssueContextMenu = ({ data }: { data: IssueResponse }) => { | |
return ( | |
<DropdownMenu> | |
{data.operations.reduce( | |
(result, { name, url: givenUrl, internal_legacy_field }) => { | |
let url = givenUrl; | |
if (Object.hasOwn(URL_OVERRIDE_FIELDS, internal_legacy_field)) { | |
url = URL_OVERRIDE_FIELDS[internal_legacy_field]; | |
} | |
if (!SKIP_FIELDS.includes(internal_legacy_field)) { | |
result.push( | |
DIALOG_FIELDS.includes(internal_legacy_field) ? ( | |
<ButtonMenuItem key={name} name={name} /> | |
) : ( | |
<LinkMenuItem key={name} name={name} url={url ?? ""} /> | |
), | |
); | |
} | |
return result; | |
}, | |
[] as React.ReactNode[], | |
)} | |
</DropdownMenu> | |
); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// issue-context-menu | |
const DIALOG_FIELDS: string[] = ['assign-issue', 'comment-issue']; | |
function isDialogField({ url, internal_legacy_field }): boolean { | |
return DIALOG_FIELDS.includes(internal_legacy_field); | |
} | |
export const IssueContextMenu = ({ data }: { data: IssueResponse }) => { | |
const { operations } = adaptIssueResponse(data); | |
return ( | |
<DropdownMenu> | |
{operations.map(operation => { | |
return isDialogField(operation) ? ( | |
<ButtonMenuItem key={operation.name} name={operation.name} /> | |
) : ( | |
<LinkMenuItem | |
key={operation.name} | |
name={operation.name} | |
url={operation.url} | |
/> | |
); | |
})} | |
</DropdownMenu> | |
); | |
}; | |
// adapt-issue-response | |
function adaptIssueResponse(issueResponse: IssueResponse): IssueResponse { | |
return { | |
...issueResponse, | |
operations: issueResponse.operations | |
.filter(operation => !skip(operation)) | |
.map(overrideURL), | |
}; | |
} | |
const SKIP_FIELDS: string[] = ['log-work']; | |
function skip({ internal_legacy_field }) { | |
return SKIP_FIELDS.includes(internal_legacy_field); | |
} | |
const URL_OVERRIDE_FIELDS: Record<string, string> = { | |
'comment-issue': '/issues/comment', | |
}; | |
function overrideURL({ name, url: givenUrl, internal_legacy_field }) { | |
let url = givenUrl ?? ''; | |
if (Object.hasOwn(URL_OVERRIDE_FIELDS, internal_legacy_field)) { | |
url = URL_OVERRIDE_FIELDS[internal_legacy_field]; | |
} | |
return { name, url, internal_legacy_field }; | |
} | |
// boilerplate | |
type IssueResponse = { | |
operations: Array<IssueResponseOperation>; | |
}; | |
type IssueResponseOperation = { | |
name: string; | |
url: string; | |
internal_legacy_field: string | |
}; | |
const DropdownMenu = props => <div>{props.children}</div>; | |
const ButtonMenuItem = props => <div>Button - {props.name}</div>; | |
const LinkMenuItem = props => ( | |
<div> | |
LinkMenuItem - {props.name} - {props.url} | |
</div> | |
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const MENU_ITEM_COMPONENTS = [ | |
{ | |
condition: isDialogField, | |
component: ButtonMenuItem, | |
getProps: (operation) => { | |
return { | |
key: operation.name, | |
name: operation.name | |
} | |
} | |
}, | |
{ | |
condition: () => true, | |
component: LinkMenuItem, | |
getProps: (operation) => { | |
return { | |
key: operation.name, | |
name: operation.name, | |
url: operation.url | |
} | |
} | |
} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment