Skip to content
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

feat: [M3-7673] - Add Account Limit support ticket to Linode Create flow #10620

Merged

Conversation

mjac0bs
Copy link
Contributor

@mjac0bs mjac0bs commented Jun 26, 2024

Description 📝

This PR adds a new type of support ticket form: the account limit ticket. Currently, when creating a Linode and a user has:

  • reached a limit on their account that prevents them from deploying the selected Linode plan
    or
  • reached the limit for the number of active services on their account

a conditional error notice is displayed. Clicking the contact support link the user is redirected to the Support page and now, in this PR, a new support ticket dialog with custom account-limit-related fields is displayed. Once submitted by the user, the support team can determine if the user is eligible to have access to more Linodes and/or larger plans. According to Customer Support, this is one of the top requests they receive from users. Similar to the SMTP ticket form, this change aims to improve the user experience and reduce the amount of back-and-forth between customers and Support when handling requests.

Note

This PR only links this account limit support ticket in the Linode Create flow, to start. It will be added to the rest of the flows that users can encounter this notice in follow up PRs.

Follow up tasks:

  • Be able to pass data from the submitted form to pre-populate a field like the Linode Plan selection (M3-8336)
  • Add the Account Limit support ticket to other product create pages (M3-8335)

Changes 🔄

  • Adds a new support ticket type: accountLimit
  • Adds new account limit support ticket fields
  • Adds a validation schema
  • Adds an integration test case
  • Handles the already-globally-intercepted support ticket API error with JSX on the Linode Create flows to be able to link to this new ticket type when the expected error text is present in the error message

Target release date 🗓️

7/22

Preview 📷

Description Before After
Error notice v1: Screenshot 2024-07-08 at 1 30 29 PM Screenshot 2024-07-08 at 1 50 22 PM v2: Screenshot 2024-07-08 at 1 31 28 PM Screenshot 2024-07-08 at 1 49 44 PM No change
Linked support ticket a general support ticket Screenshot 2024-07-08 at 1 30 43 PM
Submitted ticket N/A Screenshot 2024-07-08 at 1 39 33 PM

How to test 🧪

Prerequisites

(How to setup test environment)

  • Please test this on your dev account so we don't bother Customer Support with real tickets.
  • Please test these changes on Linode Create flow v1 and v2.
  • Check out this PR and go to http://localhost:3000/linodes/create.
  • Log into admin and be ready to change some things on your dev account.

Verification steps

(How to verify changes)

  • In admin, set your reputation to 0.

  • Fill out the linode form and try to create the linode.

  • Confirm that the UI displays an error notice when user has reached a limit on their account that prevents them from deploying the selected Linode plan: A limit on your account is preventing the deployment of the selected Linode plan. To request access to the plan, please contact Support and provide the Linode plan name.

  • In admin, reset your reputation to its previous value and set your thing limit to 0.

  • Fill out the linode form and try to create the linode.

  • Confirm that the UI displays an error notice when user has reached a limit for the number of active services on their account: You’ve reached a limit for the number of active services on your account. Please contact Support to request an increase and provide the total number of services you may need.

For each of the above possible limit errors:

  • Confirm that clicking "contact Support" redirects you to the support ticket landing page with a new Account Limit ticket open.

  • Confirm that the ticket title is always "Account Limit Increase" and the First/Last Name and Company fields are pre-populated, if you have that data on your account.

  • Try to submit the ticket and confirm validation errors show for any required fields that aren't filled out.

  • Fill out fields and submit the ticket. Confirm that you are redirected to the ticket details page, and the ticket body lists the questions and answers from the ticket.

  • Confirm no regressions to other ticket types

  • Remember to restore all values in admin to their state prior to testing!

  • Verify that all test cases in Cypress pass and the added test coverage for this PR looks good:

yarn cy:run -s "cypress/e2e/core/helpAndSupport/open-support-ticket.spec.ts"

As an Author I have considered 🤔

Check all that apply

  • 👀 Doing a self review
  • ❔ Our contribution guidelines
  • 🤏 Splitting feature into small PRs
  • ➕ Adding a changeset
  • 🧪 Providing/Improving test coverage
  • 🔐 Removing all sensitive information from the code and PR description
  • 🚩 Using a feature flag to protect the release
  • 👣 Providing comprehensive reproduction steps
  • 📑 Providing or updating our documentation
  • 🕛 Scheduling a pair reviewing session
  • 📱 Providing mobile support
  • ♿ Providing accessibility support

@mjac0bs mjac0bs self-assigned this Jun 26, 2024
@mjac0bs mjac0bs force-pushed the M3-7673-create-linode-plan-limit-support-modal branch from c2fc27d to 001ae14 Compare June 27, 2024 23:32
@mjac0bs mjac0bs force-pushed the M3-7673-create-linode-plan-limit-support-modal branch from a7482e9 to 272e246 Compare July 5, 2024 20:12
@mjac0bs mjac0bs marked this pull request as ready for review July 8, 2024 20:56
@mjac0bs mjac0bs requested review from a team as code owners July 8, 2024 20:56
@mjac0bs mjac0bs requested review from cliu-akamai, bnussman-akamai and jaalah-akamai and removed request for a team July 8, 2024 20:56
@mjac0bs mjac0bs changed the title feat: [M3-7673] - Add Account Limit support ticket feat: [M3-7673] - Add Account Limit support ticket to Linode Create flow Jul 8, 2024
Copy link

github-actions bot commented Jul 8, 2024

Coverage Report:
Base Coverage: 82.48%
Current Coverage: 82.34%


export interface TicketTypeData {
dialogTitle: string;
helperText: JSX.Element | string;
ticketTitle?: string;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated TICKET_TYPE_MAP to include a default ticket title for different ticket types, rather than handle this in the SupportLink. So, a SupportLink can either pass in a title as a prop (done with SMTP since it includes the linode name), or if they pass in a ticket type, we can get and prepopulate the right title for the ticket type via _prefilledTicketType.

) : generalError && typeof generalError !== 'string' ? (
<Notice spacingTop={8} variant="error">
<SupportTicketError
entityType="linode_id"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are passing the entityType because it is used for the following fields:

Screenshot 2024-07-08 at 2 09 00 PM

The goal is to be able to reuse this account limit form for limits encountered on any entity type. Here, it's the Linode flow, and this is how to distinguish that. In a follow up PR, if this error were encountered when trying to create a Volume, we would show "volume" in place of Linode and not show the plan type field.

We don't have an entityId, so that remains undefined, and we handle that this later before form submission here. Admittedly, it feels a little hacky. Open to other approaches, this just used our existing entityType prop.

control={control}
name="companyName"
/>
<SupportTicketProductSelectionFields ticketType="accountLimit" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than have to use all the same queries for entities, I opted to modify SupportTicketProductSelectionFields to include a field that will use those queries if the ticket type is accountLimit.

Comment on lines +180 to +196
{ticketType === 'accountLimit' ? (
<Controller
render={({ field, fieldState }) => (
<TextField
data-qa-ticket-number-of-entities
errorText={fieldState.error?.message}
helperText={`Current number of ${_entityType}: ${entityOptions.length}`}
label={ACCOUNT_LIMIT_FIELD_NAME_TO_LABEL_MAP.numberOfEntities}
name="numberOfEntities"
onChange={field.onChange}
placeholder={`Enter total number of ${_entityType}`}
value={field.value}
/>
)}
control={control}
name="numberOfEntities"
/>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is that field I mentioned in SupportTicketAccountLimitFields.

image

Comment on lines +200 to +220
render={({ field }) => (
<Autocomplete
onChange={(e, id) =>
setValue('entityId', id ? String(id?.value) : '')
}
data-qa-ticket-entity-id
disabled={entityOptions.length === 0}
errorText={
entityError ||
fieldState.error?.message ||
errors.entityId?.message
}
inputValue={entityInputValue}
label={ENTITY_ID_TO_NAME_MAP[entityType] ?? 'Entity Select'}
loading={areEntitiesLoading}
onInputChange={(e, value) => field.onChange(value ? value : '')}
options={entityOptions}
placeholder={`Select a ${ENTITY_ID_TO_NAME_MAP[entityType]}`}
value={selectedEntity}
onChange={(_e, type) => {
// Don't reset things if the type hasn't changed.
if (type.value === entityType) {
return;
}
field.onChange(type.value);
setValue('entityId', '');
setValue('entityInputValue', '');
clearErrors('entityId');
}}
data-qa-ticket-entity-type
disableClearable
label="What is this regarding?"
options={topicOptions}
value={selectedTopic}
/>
)}
control={control}
name="entityInputValue"
name="entityType"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of this stuff didn't change, think it's just diff indentation.

Comment on lines +106 to +108
numberOfEntities: 'Total number of entities you need?',
useCase:
'A detailed description of your use case and why you need access to more/larger entities',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mocks use the entity typein place of "entities", but this was more straight-forward copy to keep generic instead of using string manipulation. Going to check with UX on whether "entity" is fine, or actual entity type is desired.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the file that handles the support error, which has already been globally intercepted and the error.message has been converted to JSX. It is very similar to SupportError.tsx. I kept both for now, since this PR is only focused on the Linode Create flow, but in the future, I don't think we'll have much use for intercepting support errors globally, since what type of support error we will want to render depends on where we are in the app.

@jaalah-akamai
Copy link
Contributor

  • ✅ Confirmed both UI error notices
  • ✅ Confirmed "contact Support" redirects you to the support ticket landing page with a new Account Limit ticket open.
  • ✅ Confirmed that the ticket title is always "Account Limit Increase" and the First/Last Name and Company fields are pre-populated, if you have that data on your account.
  • ✅ No apparent regressions

@jaalah-akamai
Copy link
Contributor

Do we expect the scroll-to-error to work for v1 or just v2?

@mjac0bs
Copy link
Contributor Author

mjac0bs commented Jul 9, 2024

Do we expect the scroll-to-error to work for v1 or just v2?

@jaalah-akamai It's supposed to be working for v1, based on our recent implementation... but you're right that it's not the case here.

It's unrelated to this PR, but I'll make a bug ticket if there isn't an existing one so we can look into why scrollIntoViewv2 isn't working here after the switch to the new function. (Edit: M3-8341)

@mjac0bs mjac0bs added the Add'tl Approval Needed Waiting on another approval! label Jul 10, 2024
Copy link
Member

@bnussman-akamai bnussman-akamai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Form looks good!
Currently, I'm getting an API error that is not surfaced to the user

Details

Currently running into this error

{
  "reason": "The provided ID did not match any existing Linodes.",
  "field": "linode_id"
}

I see Cloud Manager sending this payload

{
    "description": "**Business or company name**\nLinode\n\n**First and last name**\nBanks Nussman\n\n**Total number of entities you need?**\n637285\n\n**Which Linode plan do you need access to?**\nDedicated 5.3GB\n\n**A detailed description of your use case and why you need access to more/larger entities**\nI need to host my cat blog on 637285 Linodes\n\n**Links to public information - e.g. your business or application's website, Twitter profile, GitHub, etc.**\nhttps://test.com\n\n## testing\n\n- Testing markdown",
    "linode_id": 0,
    "summary": "Account Limit Increase"
}

Screenshot 2024-07-11 at 10 12 54 AM

Comment on lines 319 to 335
// If this is an account limit ticket, we needed the entity type but won't actually send a valid entity selection.
// Reset the entity type and id back to defaults.
const _entityType =
ticketType === 'accountLimit' ? 'general' : values.entityType;
const _entityId = ticketType === 'accountLimit' ? '' : values.entityId;

if (!['general', 'none'].includes(_entityType) && !_entityId) {
form.setError('entityId', {
message: `Please select a ${ENTITY_ID_TO_NAME_MAP[entityType]}.`,
});

return;
}
return;
}
setSubmitting(true);

createSupportTicket({
[_entityType]: Number(_entityId),
Copy link
Contributor Author

@mjac0bs mjac0bs Jul 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bnussman-akamai Thanks for the catch - I thought I'd fixed this. I originally had this using resetField and was intending to reset to form defaults. I also tried specifying the defaults (e.g. form.resetField('entityType', {defaultValue: 'general'})) and wasn't seeing that work as I expected. Not sure if you know a correct way to do this? (Basically, we don't want to surface that error and we want to ignore the fact that we passed in an entity type, because its purpose was only to determine how we should populate the limit form fields; no actual Linode entity existed.)

With the above changes, we're not relying on updating form state, but this should be working:

Screen.Recording.2024-07-15.at.1.45.52.PM.mov

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking resetField wasn't working because once we're in the handleSubmit, the values won't change, but I might be missing something.

I think the updated solution looks good!

Copy link
Member

@bnussman-akamai bnussman-akamai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Form works as expected ✅ Thanks for including testing!

@mjac0bs mjac0bs added Approved Multiple approvals and ready to merge! and removed Add'tl Approval Needed Waiting on another approval! Ready for Review labels Jul 16, 2024
@mjac0bs mjac0bs merged commit 0516f3f into linode:develop Jul 16, 2024
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Approved Multiple approvals and ready to merge!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants