Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/actions/promocode-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ const normalizeEntity = (entity) => {
normalizedEntity.tags = entity.tags.map((e) => e.tag);
}

if (Array.isArray(entity.allowed_ticket_types)) {
normalizedEntity.allowed_ticket_types = entity.allowed_ticket_types.map(
(tt) => (typeof tt === "object" && tt !== null ? tt.id : tt)
);
}

delete normalizedEntity.owner;
delete normalizedEntity.owner_id;
delete normalizedEntity.speaker;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,3 +600,37 @@ describe("regression — non-DomainAuthorized classes are unaffected by the layo
}
);
});

describe("regression — handleSubmit must not dehydrate allowed_ticket_types", () => {
// Reproduces the "Ticket Types reverts to undefined" bug (Jam
// b1566c62-c802-4f43-b093-9c5c2f5a5fde, ClickUp 86b9v01bt). Pre-fix,
// handleSubmit mutated state.entity.allowed_ticket_types from [{id, name}]
// to [id]; on a 412, the form re-rendered with raw IDs, and the
// openstack-uicore TicketTypesInput's getOptionLabel = `${e.name}` produced
// the literal string "undefined" for each chip. The action layer
// (normalizeEntity in promocode-actions.js) is responsible for the
// hydrated → API-shape conversion; the form must hand off untouched
// option objects.
it("passes onSubmit an entity whose allowed_ticket_types retain {id,name} objects", () => {
const onSubmit = jest.fn();
const ticketType = { id: 197, name: "Early Access Members" };
renderForm(
baseEntity({
class_name: "DOMAIN_AUTHORIZED_PROMO_CODE",
allowed_email_domains: ["@valid.com"],
allowed_ticket_types: [ticketType]
}),
{ onSubmit }
);

fireEvent.click(screen.getByRole("button", { name: /save/i }));

expect(onSubmit).toHaveBeenCalledTimes(1);
const submittedEntity = onSubmit.mock.calls[0][0];
expect(submittedEntity.allowed_ticket_types).toEqual([ticketType]);
expect(submittedEntity.allowed_ticket_types[0]).toMatchObject({
id: 197,
name: "Early Access Members"
});
});
});
6 changes: 0 additions & 6 deletions src/components/forms/promocode-form/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,6 @@ class PromocodeForm extends React.Component {
const { entity } = this.state;
const typeScope = this.fragmentParser.getParam("type");

if (entity.allowed_ticket_types.length > 0) {
entity.allowed_ticket_types = entity.allowed_ticket_types.map(
(tt) => tt.id
);
}

if (this.validate()) {
onSubmit(entity, typeScope === "sponsor");
}
Expand Down
Loading