Skip to content

Flyouts POC + clean up#535

Open
belleklaviyo wants to merge 25 commits intofeat/iaf-flyoutsfrom
feat/flyouts-forms
Open

Flyouts POC + clean up#535
belleklaviyo wants to merge 25 commits intofeat/iaf-flyoutsfrom
feat/flyouts-forms

Conversation

@belleklaviyo
Copy link
Copy Markdown
Contributor

@belleklaviyo belleklaviyo commented Mar 30, 2026

Description

This was the original POC work. The branch was misnamed feat/flyouts-forms but will be going into an actual feature branch feat/iaf-flyouts

Due Diligence

  • I have tested this on a simulator or a physical device.
  • I have added sufficient unit/integration tests of my changes.
  • I have adjusted or added new test cases to team test docs, if applicable.
  • I am confident these changes are compatible with all iOS and XCode versions the SDK currently supports.

Release/Versioning Considerations

  • Patch Contains internal changes or backwards-compatible bug fixes.
  • Minor Contains changes to the public API.
  • Major Contains breaking changes.
  • Contains readme or migration guide changes.
    • If so, please merge to a feature branch so documentation updates only go live upon official release.
  • This is planned work for an upcoming release.
    • If no, author or reviewer should account for this in a release plan, or describe why not below.

Changelog / Code Overview

Test Plan

Related Issues/Tickets

Copy link
Copy Markdown
Contributor

@ab1470 ab1470 left a comment

Choose a reason for hiding this comment

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

btw sorry for hitting the "request changes" but I think I need to either do that or "Approve" for SLO purposes

case .formWillAppear:
let payload = try? container.decode(FormWillAppearPayload.self, forKey: .data)
self = .formWillAppear(formId: payload?.formId, formName: payload?.formName)
let decodedData = try container.decode(AnyCodable.self, forKey: .data)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

still thinking about this and whether there's an alternative to using AnyCodable here, will get back to you but first I'll submit my review so you can look at my other comments

@belleklaviyo belleklaviyo changed the base branch from master to feat/iaf-flyouts April 3, 2026 13:23
@belleklaviyo
Copy link
Copy Markdown
Contributor Author

to clean up the git history, I created a new feature branch feat/iaf-flyouts that this cleaned up POC will be merged into, so it'll be one clean commit. then other work (like #537) can be cleanly merged in as well.

@belleklaviyo belleklaviyo changed the title feat/flyouts forms Flyouts POC + clean up Apr 3, 2026
… events

Combines flyout/flexible form layout support (IAFWindowManager, FormLayout,
FormPosition) with form-context propagation through lifecycle events
(formId/formName in dismiss and formDisappeared events).

Conflict resolutions:
- IAFLifecycleEvent: keep withLayout param on present, add formId/formName to dismiss
- IAFNativeBridgeEvent: keep formWillAppear(Data) for layout decoding; add
  formDisappeared(formId:formName:) and FormContextPayload from iaf-flyouts
- IAFWebViewModel: keep HEAD layout-decoding path for formWillAppear; adopt
  case let .formDisappeared(formId, formName) from iaf-flyouts
- IAFPresentationManager: thread formId/formName through presentForm and
  presentFormAsModal; keep InAppWindowManager guard in destroyWebView;
  adopt effectiveFormId/Name fallback in dismissForm
- FormLifecycleHandlerTests: adopt iaf-flyouts tearDown (no handleFormEvent
  reset needed since context now flows through events)

Fix: correct withLayout: label in pattern matches for IAFLifecycleEvent.present
in IAFPresentationManager and IAFWebViewModelTests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
self = .formWillAppear(formId: payload?.formId, formName: payload?.formName)
let decodedData = try container.decode(AnyCodable.self, forKey: .data)
let data = try JSONEncoder().encode(decodedData)
self = .formWillAppear(data)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

formWillAppear decode now throws on missing data

Medium Severity

The formWillAppear decoding changed from try? (graceful fallback) to try (throwing). If the JS bridge sends a formWillAppear event with a missing or null data field, the entire event decode now throws, and the form silently fails to present. Previously it would still create the event with nil values and present a fullscreen form. The sibling formDisappeared case still uses try?, making this inconsistency likely unintentional.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@ab1470 if you're proposing some decoding improvements this may be addressed by your PR here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

yeah that's it. I would love to avoid AnyCodable if possible, my PR is a vibe-coded possible solution to doing that

…e handshake test

Flexible form presentation was not setting currentFormId/currentFormName,
causing dismissForm/destroyWebView to lose form identity on dismiss if the
bridge sends nil identifiers. Mirrors the existing modal path behaviour.

Also updates the handshake snapshot test to expect formWillAppear v2,
matching the version bump already in IAFNativeBridgeEvent.swift.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

let lifecycleTask = Task {
for await event in viewModel.formLifecycleStream {
if case let .present(formId, formName) = event {
if case let .present(formId, formName, withLayout: layout) = event {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Test expects old handshake version, will fail

Medium Severity

The testInjectHandshakeAttribute test in IAFWebViewModelTests.swift still expects formWillAppear at version: 1, but the production code in IAFNativeBridgeEvent.version was changed to return 2 for .formWillAppear. The corresponding test in IAFNativeBridgeEventTests.swift was correctly updated to version 2, but this test was missed. This will cause a test failure.

Additional Locations (1)
Fix in Cursor Fix in Web

@belleklaviyo belleklaviyo marked this pull request as ready for review April 3, 2026 21:00
@belleklaviyo belleklaviyo requested a review from a team as a code owner April 3, 2026 21:00
@klaviyoit klaviyoit requested a review from evan-masseau April 3, 2026 21:00
Copy link
Copy Markdown
Contributor

@evan-masseau evan-masseau left a comment

Choose a reason for hiding this comment

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

Commenting to silence reminders for now, since there's already some pending feedback. Will get back to this once feedback addressed and/or once i've had time to manually test. My read-thru won't be that helpful anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants