-
Notifications
You must be signed in to change notification settings - Fork 408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use target endpoints for Service Catalog list and item #544
Use target endpoints for Service Catalog list and item #544
Conversation
3c88d26
to
0136e2f
Compare
const data = await response.json(); | ||
if (response.ok) { | ||
setServiceCatalogItem(data.service_catalog_item); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we move const data = ....
to the if block?
const data = await response.json(); | |
if (response.ok) { | |
setServiceCatalogItem(data.service_catalog_item); | |
} | |
if (response.ok) { | |
const data = await response.json(); | |
setServiceCatalogItem(data.service_catalog_item); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we can do this, I moved it.
if (response.ok) { | ||
setServiceCatalogItem(data.service_catalog_item); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also notice that we are not handling the case where the request is not successful. Shouldn't we at least log the issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see this pattern in other places but we definitely will introduce some proper error handling with logging.
baseLocale, | ||
hasAtMentions, | ||
userRole, | ||
organizations, | ||
userId, | ||
brandId, | ||
}: ServiceCatalogItemPageProps) { | ||
const [isExpanded, setIsExpanded] = useState<boolean>(false); | ||
const [serviceCatalogItem, setServiceCatalogItem] = | ||
useState<ServiceCatalogItem>({} as ServiceCatalogItem); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could it be set to null
or undefined
instead of {}
? e.g.:
useState<ServiceCatalogItem | undefined>();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I changed it
const toggleDescription = () => { | ||
setIsExpanded(!isExpanded); | ||
}; | ||
useEffect(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be nice to extract this into a useServiceCatalogItem
hook to streamline this component a bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I moved it to hook, also we can later move all of the hooks to the hooks folder as we were talking
setShowToggleButton(false); | ||
} | ||
} | ||
}, [description]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to do handle the toggle based on the length
of the description instead of the height?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it to length but I'm not sure if the DESCRIPTION_LENGTH_THRESHOLD = 250
is ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can revise it with design later with design 👍🏼
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it might differ, letters have different width so it might be more characters but with letters that are thin or the other way around. So I don't think description length based on characters count is not good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I know, this is why I think we should set a higher value, or eventually go back to the previous approach.
If we set a higher value, let's say for example 350 characters, it may happen that we will have like 5 rows and we don't show the collapsible button. I don't think it is a big deal if we don't always show exactly 3 lines.
The important thing is that we find a good enough threshold to avoid showing the button when there is no more content to show, and this can be tricky especially considering that we will going to support other languages with different characters sets in the future.
On the other hand, the previous approach is more complex, but if it is the only reliable one maybe we should use it. wdyt @luis-almeida?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're not using a monospace font so I don't think it's an issue that the rows we end up with might differ a bit.
It's considerably simpler to do the check based on the based on the description.length
so I'd go with that approach. We could also just have it in a one-liner without the need for state and effect as mentioned in the other comment 👍🏼
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me safe length is about 270 characters, 350 is too much as from what I've tested. We could also change styling and remove caping it to 3 lines but have some fixed height of the container for description, what is overflowing will be hidden and we will show a button.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can try 270
👍🏼 I think this is something we can always change entirely if it doesn't work.
But I think still worth it to try start with the simpler approach.
@@ -90,12 +90,14 @@ export function useItemFormFields( | |||
|
|||
useEffect(() => { | |||
const fetchAndSetFields = async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here: could be nice to extract this into a useTicketFields
hook.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it too much hooks? Because in this case useItemFormFields will only call another hook and pass fields and onChange method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's away to abstract the data loading part so the component can be a bit more simple and just hold the rendering logic. But it's fine to leave it here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will leave it as it is not rendering anything but returning data to the component.
templates/service_page.hbs
Outdated
@@ -14,13 +14,18 @@ | |||
const settings = {{json settings}}; | |||
const container = document.getElementById("service-catalog-item"); | |||
|
|||
// Extract the ID from the URL | |||
const url = window.location.href; | |||
const id = url.substring(url.lastIndexOf('/') + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
window.location.href
will return query params as well if there's ever some and that might break this logic.
A more resilient way would be window.location.pathname.split("/").pop()
.
We might as well consider exposing it via curlybars at some point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I changed that, yes it is only for EAP as I wrote in the description
// Extract the ID from the URL | ||
const url = window.location.href; | ||
const id = url.substring(url.lastIndexOf('/') + 1); | ||
|
||
const props = { | ||
baseLocale: {{json help_center.base_locale}}, | ||
hasAtMentions: {{json help_center.at_mentions_enabled}}, | ||
userRole: {{json user.role}}, | ||
userId: {{json user.id}}, | ||
brandId: {{json brand.id}}, | ||
organizations: {{json user.organizations}}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit as it's not related to this PR but we might not be using all these properties in the app.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we will be sure what type of fields we will have we can revise this.
0136e2f
to
0c8c482
Compare
@@ -85,6 +85,7 @@ | |||
{{/if}} | |||
<li class="item">{{link 'community' role="menuitem"}}</li> | |||
<li class="item">{{link 'new_request' role="menuitem" class='submit-a-request'}}</li> | |||
<li class="item"><a href="/hc/en-us/services">Request a service</a></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this as I saw we are missing a button in mobile menu
try { | ||
const response = await fetch( | ||
`/api/v2/help_center/service_catalog/items/${serviceItemId}` | ||
); | ||
const data = await response.json(); | ||
setServiceCatalogItem(data.service_catalog_item); | ||
} catch (error) { | ||
console.error("Error fetching service catalog item:", error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I'm missing something here, looks like we are covering only the request happy path, ie when fetch returns a 200 response. What would happen if we get 404
or 503
?
Shouldn't we check for response.ok or !response.ok
and provide some error handling?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true I missed that. Can we check response.ok
and throw an error so it falls in catch
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I changed it to your suggestion.
? `/api/v2/help_center/service_catalog/items?page[size]=16&${currentCursor}` | ||
: `/api/v2/help_center/service_catalog/items?page[size]=16` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I notice that the page[size] parameter is hardcoded to 16
is that intended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it to some const variable so we can change it easily.
setShowToggleButton(false); | ||
} | ||
} | ||
}, [description]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useEffect(() => { | ||
if (description.length > DESCRIPTION_LENGTH_THRESHOLD) { | ||
setShowToggleButton(true); | ||
} else { | ||
setShowToggleButton(false); | ||
} | ||
}, [description]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this complex flow with useState
and useEffect
. We could just do const showToggleButton = description.length > DESCRIPTION_LENGTH_THRESHOLD
const [isExpanded, setIsExpanded] = useState<boolean>(false); | ||
const [showToggleButton, setShowToggleButton] = useState<boolean>(false); | ||
const { t } = useTranslation(); | ||
const DESCRIPTION_LENGTH_THRESHOLD = 250; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this constant can be moved outside the component
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I moved it
if (serviceCatalogItem) { | ||
return serviceCatalogItem; | ||
} else return undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need this? Cannot we just return serviceCatalogItem;
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes we can 😄 I changed that
29a3433
to
3a4bd0b
Compare
{serviceCatalogItem && ( | ||
<> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we always need to render the container and then render the content with an empty fragment (<>
) as a wrapper? Can we do return serviceCatalogItem ? <Container>...</Container> : null
or do we need the container for some reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we can do this, I changed that.
return ( | ||
<DescriptionWrapper> | ||
<ItemTitle tag="h1">{title}</ItemTitle> | ||
<CollapsibleText expanded={isExpanded}>{description}</CollapsibleText> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we set expanded={isExpanded || !showToggleButton}
, so we avoid clamping the height to 3 lines if we don't show the toggle button?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, maybe it will help with some edge cases, I added this.
3a4bd0b
to
36320e2
Compare
Description
Removed mock and call to Custom Objects API and instead use target endpoints created for Service Catalog:
For EAP we are reading the service item id from the URL as we are passing it by clicking the item on the list and redirecting. to the service item page. For GA we will read it from curlybars.
Added component for description for service item to handle showing the "read more" button when the description is shorter.
Jira issue GG-3951
Screenshots
Checklist