From aa1b8bcdb825ffca4b5e161ddfd362bbe5ca2530 Mon Sep 17 00:00:00 2001
From: TaduJR <nattysec26@gmail.com>
Date: Sun, 10 May 2026 19:30:22 +0300
Subject: [PATCH 1/9] fix: Attachment - Edit comment option is shown for .doc
 file

---
 src/libs/ReportUtils.ts               | 13 +++++++------
 src/libs/isReportMessageAttachment.ts | 25 ++++++++-----------------
 2 files changed, 15 insertions(+), 23 deletions(-)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 1480bf4a695c..6aeaac9c1fdc 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -116,7 +116,6 @@ import {getMicroSecondOnyxErrorWithTranslationKey, isReceiptError} from './Error
 import getAttachmentDetails from './fileDownload/getAttachmentDetails';
 import type {FormulaContext} from './Formula';
 import getBase62ReportID from './getBase62ReportID';
-import {isReportMessageAttachment} from './isReportMessageAttachment';
 import {formatPhoneNumber as formatPhoneNumberPhoneUtils} from './LocalePhoneNumber';
 import {translateLocal} from './Localize';
 import Log from './Log';
@@ -5024,13 +5023,16 @@ function canEditFieldOfMoneyRequest({
  * Can only edit if:
  *
  * - It was written by the current user
- * - It's an ADD_COMMENT that is not an attachment
+ * - It's an ADD_COMMENT or IOU action
+ * - It's not an optimistic attachment (still uploading)
  * - It's an expense where conditions for modifications are defined in canEditMoneyRequest method
  * - It's not pending deletion
  */
 function canEditReportAction(reportAction: OnyxInputOrEntry<ReportAction>, linkedTransaction: OnyxEntry<Transaction>): boolean {
     const isCommentOrIOU = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT || reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU;
-    const message = reportAction ? getReportActionMessageReportUtils(reportAction) : undefined;
+
+    // Block editing only while the attachment is still uploading; once synced, attachments are editable.
+    const isOptimisticAttachment = !!reportAction?.isOptimisticAction && (!!reportAction?.isAttachmentOnly || !!reportAction?.isAttachmentWithText);
 
     // For money request actions on settled/approved/closed expense reports, the action cannot be edited.
     // canEditMoneyRequest has an admin/manager bypass for field-level edits (via canEditFieldOfMoneyRequest),
@@ -5048,9 +5050,8 @@ function canEditReportAction(reportAction: OnyxInputOrEntry<ReportAction>, linke
     return !!(
         reportAction?.actorAccountID === deprecatedCurrentUserAccountID &&
         isCommentOrIOU &&
-        (!isMoneyRequestAction(reportAction) || canEditMoneyRequest(reportAction, linkedTransaction)) && // Returns true for non-IOU actions
-        !isReportMessageAttachment(message) &&
-        ((!reportAction.isAttachmentWithText && !reportAction.isAttachmentOnly) || !reportAction.isOptimisticAction) &&
+        (!isMoneyRequestAction(reportAction) || canEditMoneyRequest(reportAction, linkedTransaction)) &&
+        !isOptimisticAttachment &&
         !isDeletedAction(reportAction) &&
         !isCreatedTaskReportAction(reportAction) &&
         reportAction?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE
diff --git a/src/libs/isReportMessageAttachment.ts b/src/libs/isReportMessageAttachment.ts
index 662d2e19922f..332630194ca8 100644
--- a/src/libs/isReportMessageAttachment.ts
+++ b/src/libs/isReportMessageAttachment.ts
@@ -1,37 +1,28 @@
-import {Str} from 'expensify-common';
 import CONST from '@src/CONST';
 import type {Message} from '@src/types/onyx/ReportAction';
 
 const attachmentRegex = new RegExp(` ${CONST.ATTACHMENT_SOURCE_ATTRIBUTE}="(.*)"`, 'i');
+const attachmentOnlyHtmlRegex = /^\s*<(?:img|a|video)\s/i;
 
 /**
- * Check whether a report action is Attachment or not.
- * Ignore messages containing [Attachment] as the main content. Attachments are actions with only text as [Attachment].
- *
- * @param message report action's message as text, html and translationKey
+ * Returns true for attachment-only messages (no user-typed text), false for attachment+text and non-attachment messages.
  */
 function isReportMessageAttachment(message: Message | undefined): boolean {
     if (!message?.text || !message.html) {
         return false;
     }
 
-    if (message.translationKey) {
-        return message.text === CONST.ATTACHMENT_MESSAGE_TEXT && message.translationKey === CONST.TRANSLATION_KEYS.ATTACHMENT;
+    // Optimistic attachment-only messages carry this translationKey; the server drops it after sync.
+    if (message.translationKey === CONST.TRANSLATION_KEYS.ATTACHMENT) {
+        return true;
     }
 
-    const hasAttachmentHtml = attachmentRegex.test(message.html);
-
-    if (!hasAttachmentHtml) {
+    if (!attachmentRegex.test(message.html)) {
         return false;
     }
 
-    const isAttachmentMessageText = message.text === CONST.ATTACHMENT_MESSAGE_TEXT;
-
-    if (isAttachmentMessageText) {
-        return true;
-    }
-
-    return Str.isVideo(message.text);
+    // Attachment-only HTML starts with the attachment tag; attachment+text has user content before it.
+    return attachmentOnlyHtmlRegex.test(message.html);
 }
 
 // eslint-disable-next-line import/prefer-default-export

From 0d4e9d2e53e19d1f05ce2e7ba56a2dc066614070 Mon Sep 17 00:00:00 2001
From: TaduJR <nattysec26@gmail.com>
Date: Fri, 15 May 2026 21:13:24 +0300
Subject: [PATCH 2/9] refactor: use htmlparser2 for attachment-only detection

---
 src/libs/isReportMessageAttachment.ts | 31 +++++++++++++++++++++------
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/src/libs/isReportMessageAttachment.ts b/src/libs/isReportMessageAttachment.ts
index 332630194ca8..e8a289ca379c 100644
--- a/src/libs/isReportMessageAttachment.ts
+++ b/src/libs/isReportMessageAttachment.ts
@@ -1,8 +1,8 @@
+import {Parser as HtmlParser} from 'htmlparser2';
 import CONST from '@src/CONST';
 import type {Message} from '@src/types/onyx/ReportAction';
 
-const attachmentRegex = new RegExp(` ${CONST.ATTACHMENT_SOURCE_ATTRIBUTE}="(.*)"`, 'i');
-const attachmentOnlyHtmlRegex = /^\s*<(?:img|a|video)\s/i;
+const ATTACHMENT_TAGS = new Set(['a', 'img', 'video']);
 
 /**
  * Returns true for attachment-only messages (no user-typed text), false for attachment+text and non-attachment messages.
@@ -17,12 +17,29 @@ function isReportMessageAttachment(message: Message | undefined): boolean {
         return true;
     }
 
-    if (!attachmentRegex.test(message.html)) {
-        return false;
-    }
+    // First node decides: attachment tag → attachment-only; anything else (text, plain link, mention) → attachment+text.
+    let result = false;
+    let firstNodeSeen = false;
+
+    const parser = new HtmlParser({
+        ontext: (text) => {
+            if (firstNodeSeen || !text.trim()) {
+                return;
+            }
+            firstNodeSeen = true;
+        },
+        onopentag: (name, attribs) => {
+            if (firstNodeSeen) {
+                return;
+            }
+            firstNodeSeen = true;
+            result = ATTACHMENT_TAGS.has(name) && !!attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE];
+        },
+    });
+    parser.write(message.html);
+    parser.end();
 
-    // Attachment-only HTML starts with the attachment tag; attachment+text has user content before it.
-    return attachmentOnlyHtmlRegex.test(message.html);
+    return result;
 }
 
 // eslint-disable-next-line import/prefer-default-export

From 21b9a79815dba6f20be73f0d7b40dd044235f834 Mon Sep 17 00:00:00 2001
From: TaduJR <nattysec26@gmail.com>
Date: Fri, 15 May 2026 21:19:27 +0300
Subject: [PATCH 3/9] chore: whitelist ontext in cspell.json

---
 cspell.json | 1 +
 1 file changed, 1 insertion(+)

diff --git a/cspell.json b/cspell.json
index 6992446943a2..5ec4129b9d9e 100644
--- a/cspell.json
+++ b/cspell.json
@@ -530,6 +530,7 @@
         "onloaderror",
         "onopentag",
         "onplayerror",
+        "ontext",
         "onxy",
         "ONYXKEY",
         "ONYXKEYS",

From d6c224c3b5d8c05ca255a2cdc26315771596e3f5 Mon Sep 17 00:00:00 2001
From: TaduJR <nattysec26@gmail.com>
Date: Sat, 16 May 2026 00:23:43 +0300
Subject: [PATCH 4/9] test: add coverage for attachment-only detection and edit
 gating

---
 tests/unit/ReportUtilsTest.ts               | 85 +++++++++++++++++++++
 tests/unit/isReportMessageAttachmentTest.ts | 74 ++++++++++++++++++
 2 files changed, 159 insertions(+)

diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts
index 6478f908203a..0a314e63eca0 100644
--- a/tests/unit/ReportUtilsTest.ts
+++ b/tests/unit/ReportUtilsTest.ts
@@ -5803,6 +5803,91 @@ describe('ReportUtils', () => {
 
             expect(canEditReportAction(moneyRequestAction, transaction)).toEqual(false);
         });
+
+        it('should return false for an optimistic attachment-only action (still uploading)', () => {
+            const transaction = createRandomTransaction(300);
+            const reportAction: ReportAction = {
+                reportActionID: '300',
+                actorAccountID: currentUserAccountID,
+                actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT,
+                message: [
+                    {
+                        type: 'COMMENT',
+                        html: '<a href="blob:..." data-expensify-source="blob:...">file.doc</a>',
+                        text: '[Attachment]',
+                    },
+                ],
+                isAttachmentOnly: true,
+                isOptimisticAction: true,
+                created: '2025-03-05 16:34:27',
+            };
+
+            expect(canEditReportAction(reportAction, transaction)).toEqual(false);
+        });
+
+        it('should return false for an optimistic attachment+text action (still uploading)', () => {
+            const transaction = createRandomTransaction(301);
+            const reportAction: ReportAction = {
+                reportActionID: '301',
+                actorAccountID: currentUserAccountID,
+                actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT,
+                message: [
+                    {
+                        type: 'COMMENT',
+                        html: 'Hi<br /><br /><a href="blob:..." data-expensify-source="blob:...">file.doc</a>',
+                        text: 'Hi\n[Attachment]',
+                    },
+                ],
+                isAttachmentWithText: true,
+                isOptimisticAction: true,
+                created: '2025-03-05 16:34:27',
+            };
+
+            expect(canEditReportAction(reportAction, transaction)).toEqual(false);
+        });
+
+        it('should return true for a synced attachment-only action (optimistic flags cleared)', () => {
+            const transaction = createRandomTransaction(302);
+            // After successData merge: isOptimisticAction=null, isAttachmentOnly persists from optimistic merge.
+            const reportAction: ReportAction = {
+                reportActionID: '302',
+                actorAccountID: currentUserAccountID,
+                actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT,
+                message: [
+                    {
+                        type: 'COMMENT',
+                        html: '<a href="https://www.expensify.com/chat-attachments/123/file.doc" data-expensify-source="https://www.expensify.com/chat-attachments/123/file.doc">file.doc</a>',
+                        text: 'file.doc https://www.expensify.com/chat-attachments/123/file.doc',
+                    },
+                ],
+                isAttachmentOnly: true,
+                isOptimisticAction: null,
+                created: '2025-03-05 16:34:27',
+            };
+
+            expect(canEditReportAction(reportAction, transaction)).toEqual(true);
+        });
+
+        it('should return true for a synced attachment+text action', () => {
+            const transaction = createRandomTransaction(303);
+            const reportAction: ReportAction = {
+                reportActionID: '303',
+                actorAccountID: currentUserAccountID,
+                actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT,
+                message: [
+                    {
+                        type: 'COMMENT',
+                        html: 'Hi<br /><br /><a href="https://www.expensify.com/chat-attachments/123/file.doc" data-expensify-source="https://www.expensify.com/chat-attachments/123/file.doc">file.doc</a>',
+                        text: 'Hi\nfile.doc https://www.expensify.com/chat-attachments/123/file.doc',
+                    },
+                ],
+                isAttachmentWithText: true,
+                isOptimisticAction: null,
+                created: '2025-03-05 16:34:27',
+            };
+
+            expect(canEditReportAction(reportAction, transaction)).toEqual(true);
+        });
     });
 
     describe('getChatByParticipants', () => {
diff --git a/tests/unit/isReportMessageAttachmentTest.ts b/tests/unit/isReportMessageAttachmentTest.ts
index 75faba9c8935..52dee4e31710 100644
--- a/tests/unit/isReportMessageAttachmentTest.ts
+++ b/tests/unit/isReportMessageAttachmentTest.ts
@@ -1,3 +1,4 @@
+import CONST from '@src/CONST';
 import type {Message} from '@src/types/onyx/ReportAction';
 import {isReportMessageAttachment} from '../../src/libs/isReportMessageAttachment';
 
@@ -21,4 +22,77 @@ describe('isReportMessageAttachment', () => {
         message = {text: '[Attachment]', html: '<a href="https://www.google.com/?data-expensify-source=" target="_blank" rel="noreferrer noopener">[Attachment]</a>', type: ''};
         expect(isReportMessageAttachment(message)).toBe(false);
     });
+
+    it('returns true for optimistic attachment-only via translationKey', () => {
+        const message: Message = {
+            text: '[Attachment]',
+            html: '<a href="blob:https://dev.new.expensify.com:8082/abc" data-expensify-source="blob:https://dev.new.expensify.com:8082/abc">sample.doc</a>',
+            type: '',
+            translationKey: CONST.TRANSLATION_KEYS.ATTACHMENT,
+        };
+        expect(isReportMessageAttachment(message)).toBe(true);
+    });
+
+    it('returns true for .doc attachment-only after OpenReport sync (text is "filename URL")', () => {
+        const message: Message = {
+            text: 'sample.doc https://staging.expensify.com/chat-attachments/4271684646135633435/w_87c70962804917e4c6866d052537133ae0a3060e.doc',
+            html: '<a href="https://staging.expensify.com/chat-attachments/4271684646135633435/w_87c70962804917e4c6866d052537133ae0a3060e.doc" data-expensify-source="https://staging.expensify.com/chat-attachments/4271684646135633435/w_87c70962804917e4c6866d052537133ae0a3060e.doc" data-attachment-id="123">sample.doc</a>',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(true);
+    });
+
+    it('returns true for .pdf attachment-only', () => {
+        const message: Message = {
+            text: 'report.pdf https://www.expensify.com/chat-attachments/123/report.pdf',
+            html: '<a href="https://www.expensify.com/chat-attachments/123/report.pdf" data-expensify-source="https://www.expensify.com/chat-attachments/123/report.pdf">report.pdf</a>',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(true);
+    });
+
+    it('returns true for video attachment-only', () => {
+        const message: Message = {
+            text: 'demo.mp4',
+            html: '<video src="https://www.expensify.com/chat-attachments/123/demo.mp4" data-expensify-source="https://www.expensify.com/chat-attachments/123/demo.mp4">demo.mp4</video>',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(true);
+    });
+
+    it('returns false for attachment+text (user text before the attachment)', () => {
+        const message: Message = {
+            text: 'Check this file\nsample.doc https://www.expensify.com/chat-attachments/123/sample.doc',
+            html: 'Check this file<br /><br /><a href="https://www.expensify.com/chat-attachments/123/sample.doc" data-expensify-source="https://www.expensify.com/chat-attachments/123/sample.doc">sample.doc</a>',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(false);
+    });
+
+    it('returns false for a leading user URL + attachment (regression guard for codex bot P2)', () => {
+        const message: Message = {
+            text: 'https://example.com check this\nsample.doc https://www.expensify.com/chat-attachments/123/sample.doc',
+            html: '<a href="https://example.com" data-raw-href="https://example.com" data-link-variant="auto" target="_blank" rel="noreferrer noopener">https://example.com</a> check this<br /><br /><a href="https://www.expensify.com/chat-attachments/123/sample.doc" data-expensify-source="https://www.expensify.com/chat-attachments/123/sample.doc">sample.doc</a>',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(false);
+    });
+
+    it('returns false for a plain user link with only data-raw-href (no attachment)', () => {
+        const message: Message = {
+            text: 'https://example.com',
+            html: '<a href="https://example.com" data-raw-href="https://example.com" target="_blank" rel="noreferrer noopener">https://example.com</a>',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(false);
+    });
+
+    it('returns false for a mention before the attachment', () => {
+        const message: Message = {
+            text: '@user check this\nsample.doc https://www.expensify.com/chat-attachments/123/sample.doc',
+            html: '<mention-user accountID="1">@user</mention-user> check this<br /><br /><a href="https://www.expensify.com/chat-attachments/123/sample.doc" data-expensify-source="https://www.expensify.com/chat-attachments/123/sample.doc">sample.doc</a>',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(false);
+    });
 });

From d42f03f1549b6976e5062e9092ef944e768f4443 Mon Sep 17 00:00:00 2001
From: TaduJR <nattysec26@gmail.com>
Date: Sat, 16 May 2026 00:33:35 +0300
Subject: [PATCH 5/9] fix: treat caption appended after attachment as
 attachment+text

---
 src/libs/isReportMessageAttachment.ts       | 32 +++++++++++++++------
 tests/unit/ReportUtilsTest.ts               |  6 ++--
 tests/unit/isReportMessageAttachmentTest.ts | 18 ++++++++++++
 3 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/src/libs/isReportMessageAttachment.ts b/src/libs/isReportMessageAttachment.ts
index e8a289ca379c..1da5b75f2a29 100644
--- a/src/libs/isReportMessageAttachment.ts
+++ b/src/libs/isReportMessageAttachment.ts
@@ -17,29 +17,43 @@ function isReportMessageAttachment(message: Message | undefined): boolean {
         return true;
     }
 
-    // First node decides: attachment tag → attachment-only; anything else (text, plain link, mention) → attachment+text.
-    let result = false;
-    let firstNodeSeen = false;
+    // Attachment-only = exactly one attachment tag and nothing else; any text/element outside it → attachment+text.
+    let attachmentCount = 0;
+    let hasOtherContent = false;
+    // Skip the filename text inside an open <a>/<video> so it isn't counted as user content.
+    let openAttachmentTag: string | null = null;
 
     const parser = new HtmlParser({
         ontext: (text) => {
-            if (firstNodeSeen || !text.trim()) {
+            if (openAttachmentTag || !text.trim()) {
                 return;
             }
-            firstNodeSeen = true;
+            hasOtherContent = true;
         },
         onopentag: (name, attribs) => {
-            if (firstNodeSeen) {
+            if (openAttachmentTag || name === 'br') {
                 return;
             }
-            firstNodeSeen = true;
-            result = ATTACHMENT_TAGS.has(name) && !!attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE];
+            if (ATTACHMENT_TAGS.has(name) && !!attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE]) {
+                attachmentCount += 1;
+                if (name === 'a' || name === 'video') {
+                    openAttachmentTag = name;
+                }
+                return;
+            }
+            hasOtherContent = true;
+        },
+        onclosetag: (name) => {
+            if (name !== openAttachmentTag) {
+                return;
+            }
+            openAttachmentTag = null;
         },
     });
     parser.write(message.html);
     parser.end();
 
-    return result;
+    return attachmentCount > 0 && !hasOtherContent;
 }
 
 // eslint-disable-next-line import/prefer-default-export
diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts
index 0a314e63eca0..12e8368cb7a2 100644
--- a/tests/unit/ReportUtilsTest.ts
+++ b/tests/unit/ReportUtilsTest.ts
@@ -5848,7 +5848,7 @@ describe('ReportUtils', () => {
 
         it('should return true for a synced attachment-only action (optimistic flags cleared)', () => {
             const transaction = createRandomTransaction(302);
-            // After successData merge: isOptimisticAction=null, isAttachmentOnly persists from optimistic merge.
+            // Post-sync state: successData clears isOptimisticAction (null in Onyx, undefined here); isAttachmentOnly persists.
             const reportAction: ReportAction = {
                 reportActionID: '302',
                 actorAccountID: currentUserAccountID,
@@ -5861,7 +5861,7 @@ describe('ReportUtils', () => {
                     },
                 ],
                 isAttachmentOnly: true,
-                isOptimisticAction: null,
+                isOptimisticAction: undefined,
                 created: '2025-03-05 16:34:27',
             };
 
@@ -5882,7 +5882,7 @@ describe('ReportUtils', () => {
                     },
                 ],
                 isAttachmentWithText: true,
-                isOptimisticAction: null,
+                isOptimisticAction: undefined,
                 created: '2025-03-05 16:34:27',
             };
 
diff --git a/tests/unit/isReportMessageAttachmentTest.ts b/tests/unit/isReportMessageAttachmentTest.ts
index 52dee4e31710..bb12c3bd869f 100644
--- a/tests/unit/isReportMessageAttachmentTest.ts
+++ b/tests/unit/isReportMessageAttachmentTest.ts
@@ -95,4 +95,22 @@ describe('isReportMessageAttachment', () => {
         };
         expect(isReportMessageAttachment(message)).toBe(false);
     });
+
+    it('returns false for an attachment with a caption appended after it (regression guard for codex bot P2)', () => {
+        const message: Message = {
+            text: 'sample.doc https://www.expensify.com/chat-attachments/123/sample.doc my caption',
+            html: '<a href="https://www.expensify.com/chat-attachments/123/sample.doc" data-expensify-source="https://www.expensify.com/chat-attachments/123/sample.doc">sample.doc</a> my caption',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(false);
+    });
+
+    it('returns true when the anchor inner text (filename) is the only text', () => {
+        const message: Message = {
+            text: 'sample.doc https://www.expensify.com/chat-attachments/123/sample.doc',
+            html: '<a href="https://www.expensify.com/chat-attachments/123/sample.doc" data-expensify-source="https://www.expensify.com/chat-attachments/123/sample.doc">sample.doc</a>',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(true);
+    });
 });

From fabe04b245d4022f4a411e14b9f4867fe5e114c2 Mon Sep 17 00:00:00 2001
From: TaduJR <nattysec26@gmail.com>
Date: Sun, 17 May 2026 23:37:37 +0300
Subject: [PATCH 6/9] refactor: rename openAttachmentTag and add
 multi-attachment-only test

---
 src/libs/isReportMessageAttachment.ts       | 16 ++++++++--------
 tests/unit/isReportMessageAttachmentTest.ts | 10 ++++++++++
 2 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/src/libs/isReportMessageAttachment.ts b/src/libs/isReportMessageAttachment.ts
index 1da5b75f2a29..a3d4748f3f8c 100644
--- a/src/libs/isReportMessageAttachment.ts
+++ b/src/libs/isReportMessageAttachment.ts
@@ -17,37 +17,37 @@ function isReportMessageAttachment(message: Message | undefined): boolean {
         return true;
     }
 
-    // Attachment-only = exactly one attachment tag and nothing else; any text/element outside it → attachment+text.
+    // Attachment-only = one or more attachment tags and nothing else; any text/element outside them → attachment+text.
     let attachmentCount = 0;
     let hasOtherContent = false;
-    // Skip the filename text inside an open <a>/<video> so it isn't counted as user content.
-    let openAttachmentTag: string | null = null;
+    // Holds the tag name of the open <a>/<video> attachment so its inner filename text isn't counted as user content.
+    let openAttachmentTagName: string | null = null;
 
     const parser = new HtmlParser({
         ontext: (text) => {
-            if (openAttachmentTag || !text.trim()) {
+            if (openAttachmentTagName || !text.trim()) {
                 return;
             }
             hasOtherContent = true;
         },
         onopentag: (name, attribs) => {
-            if (openAttachmentTag || name === 'br') {
+            if (openAttachmentTagName || name === 'br') {
                 return;
             }
             if (ATTACHMENT_TAGS.has(name) && !!attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE]) {
                 attachmentCount += 1;
                 if (name === 'a' || name === 'video') {
-                    openAttachmentTag = name;
+                    openAttachmentTagName = name;
                 }
                 return;
             }
             hasOtherContent = true;
         },
         onclosetag: (name) => {
-            if (name !== openAttachmentTag) {
+            if (name !== openAttachmentTagName) {
                 return;
             }
-            openAttachmentTag = null;
+            openAttachmentTagName = null;
         },
     });
     parser.write(message.html);
diff --git a/tests/unit/isReportMessageAttachmentTest.ts b/tests/unit/isReportMessageAttachmentTest.ts
index bb12c3bd869f..5c88e24f7d11 100644
--- a/tests/unit/isReportMessageAttachmentTest.ts
+++ b/tests/unit/isReportMessageAttachmentTest.ts
@@ -113,4 +113,14 @@ describe('isReportMessageAttachment', () => {
         };
         expect(isReportMessageAttachment(message)).toBe(true);
     });
+
+    // Multi-upload is normally split into separate actions; if multiple attachments share one message, classification stays attachment-only.
+    it('returns true for multiple attachments with no surrounding text', () => {
+        const message: Message = {
+            text: 'a.doc https://www.expensify.com/chat-attachments/1/a.doc\nb.pdf https://www.expensify.com/chat-attachments/2/b.pdf',
+            html: '<a href="https://www.expensify.com/chat-attachments/1/a.doc" data-expensify-source="https://www.expensify.com/chat-attachments/1/a.doc">a.doc</a><a href="https://www.expensify.com/chat-attachments/2/b.pdf" data-expensify-source="https://www.expensify.com/chat-attachments/2/b.pdf">b.pdf</a>',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(true);
+    });
 });

From 791171f54635067b297e953333ffed46dc3f5655 Mon Sep 17 00:00:00 2001
From: TaduJR <nattysec26@gmail.com>
Date: Mon, 18 May 2026 09:47:33 +0300
Subject: [PATCH 7/9] perf: fast-path + memoize isReportMessageAttachment

---
 src/libs/isReportMessageAttachment.ts         | 71 +++++++++++++------
 .../isReportMessageAttachment.perf-test.ts    | 37 ++++++++++
 tests/unit/isReportMessageAttachmentTest.ts   | 19 ++++-
 3 files changed, 105 insertions(+), 22 deletions(-)
 create mode 100644 tests/perf-test/isReportMessageAttachment.perf-test.ts

diff --git a/src/libs/isReportMessageAttachment.ts b/src/libs/isReportMessageAttachment.ts
index a3d4748f3f8c..275a2c8691c7 100644
--- a/src/libs/isReportMessageAttachment.ts
+++ b/src/libs/isReportMessageAttachment.ts
@@ -3,57 +3,86 @@ import CONST from '@src/CONST';
 import type {Message} from '@src/types/onyx/ReportAction';
 
 const ATTACHMENT_TAGS = new Set(['a', 'img', 'video']);
+// Leading space + `="` (not a bare substring) so a URL query param like `?data-expensify-source=` isn't a false positive.
+const ATTACHMENT_SOURCE_TOKEN = ` ${CONST.ATTACHMENT_SOURCE_ATTRIBUTE}="`;
 
-/**
- * Returns true for attachment-only messages (no user-typed text), false for attachment+text and non-attachment messages.
- */
-function isReportMessageAttachment(message: Message | undefined): boolean {
-    if (!message?.text || !message.html) {
+// Keyed by Onyx message identity: re-renders pass the same immutable object, so parse at most once per message.
+const resultCache = new WeakMap<Message, boolean>();
+
+function computeIsReportMessageAttachment(html: string, text: string, translationKey: string | undefined): boolean {
+    // Optimistic attachment-only messages carry this translationKey; the server drops it after sync.
+    if (translationKey === CONST.TRANSLATION_KEYS.ATTACHMENT) {
+        return true;
+    }
+
+    // Fast path: no source attribute → not an attachment (avoids the parser for most messages).
+    if (!html.includes(ATTACHMENT_SOURCE_TOKEN)) {
         return false;
     }
 
-    // Optimistic attachment-only messages carry this translationKey; the server drops it after sync.
-    if (message.translationKey === CONST.TRANSLATION_KEYS.ATTACHMENT) {
+    // image/video attachment-only keep text "[Attachment]"; only .doc/.pdf (text = "filename URL") need the parser.
+    if (text === CONST.ATTACHMENT_MESSAGE_TEXT) {
         return true;
     }
 
-    // Attachment-only = one or more attachment tags and nothing else; any text/element outside them → attachment+text.
-    let attachmentCount = 0;
+    let hasAttachment = false;
     let hasOtherContent = false;
-    // Holds the tag name of the open <a>/<video> attachment so its inner filename text isn't counted as user content.
-    let openAttachmentTagName: string | null = null;
+    // Depth >0 = inside the attachment's subtree; its inner nodes (filename/markup) aren't user content.
+    let depth = 0;
 
     const parser = new HtmlParser({
-        ontext: (text) => {
-            if (openAttachmentTagName || !text.trim()) {
+        ontext: (nodeText) => {
+            if (depth > 0 || !nodeText.trim()) {
                 return;
             }
             hasOtherContent = true;
         },
         onopentag: (name, attribs) => {
-            if (openAttachmentTagName || name === 'br') {
+            if (depth > 0) {
+                depth += 1;
+                return;
+            }
+            if (name === 'br') {
                 return;
             }
             if (ATTACHMENT_TAGS.has(name) && !!attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE]) {
-                attachmentCount += 1;
+                hasAttachment = true;
                 if (name === 'a' || name === 'video') {
-                    openAttachmentTagName = name;
+                    depth = 1;
                 }
                 return;
             }
             hasOtherContent = true;
         },
-        onclosetag: (name) => {
-            if (name !== openAttachmentTagName) {
+        onclosetag: () => {
+            if (depth <= 0) {
                 return;
             }
-            openAttachmentTagName = null;
+            depth -= 1;
         },
     });
-    parser.write(message.html);
+    parser.write(html);
     parser.end();
 
-    return attachmentCount > 0 && !hasOtherContent;
+    return hasAttachment && !hasOtherContent;
+}
+
+/**
+ * Returns true for attachment-only messages (no user-typed text), false for attachment+text and non-attachment messages.
+ */
+function isReportMessageAttachment(message: Message | undefined): boolean {
+    if (!message?.text || !message.html) {
+        return false;
+    }
+
+    const cached = resultCache.get(message);
+    if (cached !== undefined) {
+        return cached;
+    }
+
+    const result = computeIsReportMessageAttachment(message.html, message.text, message.translationKey);
+    resultCache.set(message, result);
+    return result;
 }
 
 // eslint-disable-next-line import/prefer-default-export
diff --git a/tests/perf-test/isReportMessageAttachment.perf-test.ts b/tests/perf-test/isReportMessageAttachment.perf-test.ts
new file mode 100644
index 000000000000..b6c5bf4024e5
--- /dev/null
+++ b/tests/perf-test/isReportMessageAttachment.perf-test.ts
@@ -0,0 +1,37 @@
+import {measureFunction} from 'reassure';
+import type {Message} from '@src/types/onyx/ReportAction';
+import {isReportMessageAttachment} from '../../src/libs/isReportMessageAttachment';
+
+const SAMPLE_MESSAGES: Message[] = [
+    // .doc attachment-only after OpenReport: text = "filename URL" (the parser-bound case)
+    {
+        text: 'sample.doc https://www.expensify.com/chat-attachments/123/w_abc.doc',
+        html: '<a href="https://www.expensify.com/chat-attachments/123/w_abc.doc" data-expensify-source="https://www.expensify.com/chat-attachments/123/w_abc.doc">sample.doc</a>',
+        type: '',
+    },
+    // image attachment-only (translationKey path)
+    {
+        text: '[Attachment]',
+        html: '<img src="https://www.expensify.com/chat-attachments/123/img.jpg" data-expensify-source="https://www.expensify.com/chat-attachments/123/img.jpg" />',
+        type: '',
+        translationKey: 'common.attachment',
+    },
+    {
+        text: 'Here is the file\nsample.pdf https://www.expensify.com/chat-attachments/123/s.pdf',
+        html: 'Here is the file<br /><br /><a href="https://www.expensify.com/chat-attachments/123/s.pdf" data-expensify-source="https://www.expensify.com/chat-attachments/123/s.pdf">sample.pdf</a>',
+        type: '',
+    },
+    {text: 'Just a normal chat message with some words in it', html: 'Just a normal chat message with some words in it', type: ''},
+    {text: 'https://example.com', html: '<a href="https://example.com" data-raw-href="https://example.com" target="_blank" rel="noreferrer noopener">https://example.com</a>', type: ''},
+];
+
+// One classification pass over a long chat history (called per message on list renders / LHN).
+const LONG_CHAT_HISTORY: Message[] = Array.from({length: 2000}, () => SAMPLE_MESSAGES).flat();
+
+test('[isReportMessageAttachment] classify a 10k-message chat history', async () => {
+    await measureFunction(() => {
+        for (const message of LONG_CHAT_HISTORY) {
+            isReportMessageAttachment(message);
+        }
+    });
+});
diff --git a/tests/unit/isReportMessageAttachmentTest.ts b/tests/unit/isReportMessageAttachmentTest.ts
index 5c88e24f7d11..31405e8443fa 100644
--- a/tests/unit/isReportMessageAttachmentTest.ts
+++ b/tests/unit/isReportMessageAttachmentTest.ts
@@ -114,7 +114,6 @@ describe('isReportMessageAttachment', () => {
         expect(isReportMessageAttachment(message)).toBe(true);
     });
 
-    // Multi-upload is normally split into separate actions; if multiple attachments share one message, classification stays attachment-only.
     it('returns true for multiple attachments with no surrounding text', () => {
         const message: Message = {
             text: 'a.doc https://www.expensify.com/chat-attachments/1/a.doc\nb.pdf https://www.expensify.com/chat-attachments/2/b.pdf',
@@ -123,4 +122,22 @@ describe('isReportMessageAttachment', () => {
         };
         expect(isReportMessageAttachment(message)).toBe(true);
     });
+
+    it('returns true for an attachment whose anchor wraps nested markup', () => {
+        const message: Message = {
+            text: 'sample.doc https://www.expensify.com/chat-attachments/123/sample.doc',
+            html: '<a href="https://www.expensify.com/chat-attachments/123/sample.doc" data-expensify-source="https://www.expensify.com/chat-attachments/123/sample.doc">pre<strong>sample</strong>.doc</a>',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(true);
+    });
+
+    it('returns false for an attachment with nested markup AND a trailing caption', () => {
+        const message: Message = {
+            text: 'sample.doc https://www.expensify.com/chat-attachments/123/sample.doc see this',
+            html: '<a href="https://www.expensify.com/chat-attachments/123/sample.doc" data-expensify-source="https://www.expensify.com/chat-attachments/123/sample.doc">pre<strong>sample</strong>.doc</a> see this',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(false);
+    });
 });

From 4edca7a1aee8357e2224ec851f72c8b0ee724d09 Mon Sep 17 00:00:00 2001
From: TaduJR <nattysec26@gmail.com>
Date: Mon, 18 May 2026 10:12:02 +0300
Subject: [PATCH 8/9] test: cover guards, translationKey semantics, and full
 attachment matrix

---
 tests/unit/ReportUtilsTest.ts               | 20 ++++++++++++
 tests/unit/isReportMessageAttachmentTest.ts | 34 +++++++++++++++++++++
 2 files changed, 54 insertions(+)

diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts
index 12e8368cb7a2..f270960eef98 100644
--- a/tests/unit/ReportUtilsTest.ts
+++ b/tests/unit/ReportUtilsTest.ts
@@ -5888,6 +5888,26 @@ describe('ReportUtils', () => {
 
             expect(canEditReportAction(reportAction, transaction)).toEqual(true);
         });
+
+        it('should return true for an optimistic plain-text comment (no attachment)', () => {
+            const transaction = createRandomTransaction(304);
+            const reportAction: ReportAction = {
+                reportActionID: '304',
+                actorAccountID: currentUserAccountID,
+                actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT,
+                message: [
+                    {
+                        type: 'COMMENT',
+                        html: 'hello',
+                        text: 'hello',
+                    },
+                ],
+                isOptimisticAction: true,
+                created: '2025-03-05 16:34:27',
+            };
+
+            expect(canEditReportAction(reportAction, transaction)).toEqual(true);
+        });
     });
 
     describe('getChatByParticipants', () => {
diff --git a/tests/unit/isReportMessageAttachmentTest.ts b/tests/unit/isReportMessageAttachmentTest.ts
index 31405e8443fa..32362d5071c3 100644
--- a/tests/unit/isReportMessageAttachmentTest.ts
+++ b/tests/unit/isReportMessageAttachmentTest.ts
@@ -140,4 +140,38 @@ describe('isReportMessageAttachment', () => {
         };
         expect(isReportMessageAttachment(message)).toBe(false);
     });
+
+    it('returns false for undefined or empty message', () => {
+        expect(isReportMessageAttachment(undefined)).toBe(false);
+        expect(isReportMessageAttachment({text: '', html: '', type: ''})).toBe(false);
+        expect(isReportMessageAttachment({text: 'x', html: undefined as unknown as string, type: ''})).toBe(false);
+    });
+
+    it('falls through when translationKey is set but is not the attachment key', () => {
+        const message: Message = {
+            text: 'sample.doc https://www.expensify.com/chat-attachments/123/sample.doc',
+            html: '<a href="https://www.expensify.com/chat-attachments/123/sample.doc" data-expensify-source="https://www.expensify.com/chat-attachments/123/sample.doc">sample.doc</a>',
+            type: '',
+            translationKey: 'common.download',
+        };
+        expect(isReportMessageAttachment(message)).toBe(true);
+    });
+
+    it('returns false for image attachment + text', () => {
+        const message: Message = {
+            text: 'check this image\n[Attachment]',
+            html: 'check this image<br /><br /><img src="https://www.expensify.com/chat-attachments/123/img.jpg" data-expensify-source="https://www.expensify.com/chat-attachments/123/img.jpg" />',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(false);
+    });
+
+    it('returns false for video attachment + text', () => {
+        const message: Message = {
+            text: 'watch this\ndemo.mp4 https://www.expensify.com/chat-attachments/123/demo.mp4',
+            html: 'watch this<br /><br /><video src="https://www.expensify.com/chat-attachments/123/demo.mp4" data-expensify-source="https://www.expensify.com/chat-attachments/123/demo.mp4">demo.mp4</video>',
+            type: '',
+        };
+        expect(isReportMessageAttachment(message)).toBe(false);
+    });
 });

From 6b0b0596ce01ef272d205f6c767a78f13055f1b8 Mon Sep 17 00:00:00 2001
From: TaduJR <nattysec26@gmail.com>
Date: Mon, 18 May 2026 10:28:31 +0300
Subject: [PATCH 9/9] fix: drop PrivatePersonalDetails merge collateral

---
 .../UpdatePrivatePersonalDetailsParams.ts     |  16 -
 src/libs/PersonalDetailsUtils.ts              |  24 --
 src/libs/actions/PersonalDetails.ts           |  53 ---
 ...atePersonalDetailsConfirmMagicCodePage.tsx |  81 ----
 .../PrivatePersonalDetailsPage.tsx            | 396 ------------------
 5 files changed, 570 deletions(-)
 delete mode 100644 src/libs/API/parameters/UpdatePrivatePersonalDetailsParams.ts
 delete mode 100644 src/pages/settings/Profile/PersonalDetails/PrivatePersonalDetailsConfirmMagicCodePage.tsx
 delete mode 100644 src/pages/settings/Profile/PersonalDetails/PrivatePersonalDetailsPage.tsx

diff --git a/src/libs/API/parameters/UpdatePrivatePersonalDetailsParams.ts b/src/libs/API/parameters/UpdatePrivatePersonalDetailsParams.ts
deleted file mode 100644
index 177a5dfacfc6..000000000000
--- a/src/libs/API/parameters/UpdatePrivatePersonalDetailsParams.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-type UpdatePrivatePersonalDetailsParams = {
-    legalFirstName: string;
-    legalLastName: string;
-    phoneNumber: string;
-    addressCity: string;
-    addressStreet: string;
-    addressStreet2: string;
-    addressZip: string;
-    addressCountry: string;
-    dob: string;
-    validateCode: string;
-    addressState: string;
-    addressProvince: string;
-};
-
-export default UpdatePrivatePersonalDetailsParams;
diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts
index 393fad87853e..81ed9e4a5909 100644
--- a/src/libs/PersonalDetailsUtils.ts
+++ b/src/libs/PersonalDetailsUtils.ts
@@ -4,8 +4,6 @@ import Onyx from 'react-native-onyx';
 import type {LocaleContextProps} from '@components/LocaleContextProvider';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
-import type {PersonalDetailsForm} from '@src/types/form';
-import INPUT_IDS from '@src/types/form/PersonalDetailsForm';
 import type {OnyxInputOrEntry, PersonalDetails, PersonalDetailsList, PrivatePersonalDetails} from '@src/types/onyx';
 import type {Address} from '@src/types/onyx/PrivatePersonalDetails';
 import type {OnyxData} from '@src/types/onyx/Request';
@@ -300,27 +298,6 @@ function getCurrentAddress(privatePersonalDetails: OnyxEntry<PrivatePersonalDeta
     return currentAddress ?? addresses?.[addresses.length - 1];
 }
 
-/**
- * Builds a PersonalDetailsForm snapshot from Onyx private details,
- * optionally layering draft values on top so in-progress edits win.
- */
-function getPrivatePersonalDetailsFormValues(privatePersonalDetails: OnyxEntry<PrivatePersonalDetails>, draftValues?: PersonalDetailsForm | null): PersonalDetailsForm {
-    const address = getCurrentAddress(privatePersonalDetails);
-    const [street1, street2] = getStreetLines(address?.street);
-    return {
-        [INPUT_IDS.LEGAL_FIRST_NAME]: draftValues?.[INPUT_IDS.LEGAL_FIRST_NAME] ?? privatePersonalDetails?.legalFirstName ?? '',
-        [INPUT_IDS.LEGAL_LAST_NAME]: draftValues?.[INPUT_IDS.LEGAL_LAST_NAME] ?? privatePersonalDetails?.legalLastName ?? '',
-        [INPUT_IDS.DATE_OF_BIRTH]: draftValues?.[INPUT_IDS.DATE_OF_BIRTH] ?? privatePersonalDetails?.dob ?? '',
-        [INPUT_IDS.PHONE_NUMBER]: draftValues?.[INPUT_IDS.PHONE_NUMBER] ?? privatePersonalDetails?.phoneNumber ?? '',
-        [INPUT_IDS.ADDRESS_LINE_1]: draftValues?.[INPUT_IDS.ADDRESS_LINE_1] ?? street1 ?? '',
-        [INPUT_IDS.ADDRESS_LINE_2]: draftValues?.[INPUT_IDS.ADDRESS_LINE_2] ?? street2 ?? '',
-        [INPUT_IDS.CITY]: draftValues?.[INPUT_IDS.CITY] ?? address?.city ?? '',
-        [INPUT_IDS.STATE]: draftValues?.[INPUT_IDS.STATE] ?? address?.state ?? '',
-        [INPUT_IDS.ZIP_POST_CODE]: draftValues?.[INPUT_IDS.ZIP_POST_CODE] ?? address?.zip ?? '',
-        [INPUT_IDS.COUNTRY]: draftValues?.[INPUT_IDS.COUNTRY] ?? address?.country ?? '',
-    };
-}
-
 /**
  * Formats an address object into an easily readable string
  *
@@ -488,7 +465,6 @@ export {
     getCurrentAddress,
     getFormattedAddress,
     getFormattedStreet,
-    getPrivatePersonalDetailsFormValues,
     getStreetLines,
     getEffectiveDisplayName,
     createDisplayName,
diff --git a/src/libs/actions/PersonalDetails.ts b/src/libs/actions/PersonalDetails.ts
index ff2c09fa89d8..b5b721145641 100644
--- a/src/libs/actions/PersonalDetails.ts
+++ b/src/libs/actions/PersonalDetails.ts
@@ -12,7 +12,6 @@ import type {
     UpdateHomeAddressParams,
     UpdateLegalNameParams,
     UpdatePhoneNumberParams,
-    UpdatePrivatePersonalDetailsParams,
     UpdatePronounsParams,
     UpdateSelectedTimezoneParams,
     UpdateUserAvatarParams,
@@ -512,57 +511,6 @@ function deleteAvatar(currentUserPersonalDetails: Pick<CurrentUserPersonalDetail
 function clearPersonalDetailsErrors() {
     Onyx.merge(ONYXKEYS.PRIVATE_PERSONAL_DETAILS, {
         errors: null,
-        errorFields: {personalDetails: null},
-    });
-}
-
-function updatePrivatePersonalDetails(values: FormOnyxValues<typeof ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM>, validateCode: string, countryCode: number) {
-    const stateValue = (values.state ?? '').trim();
-    const parameters: UpdatePrivatePersonalDetailsParams = {
-        legalFirstName: values.legalFirstName?.trim() ?? '',
-        legalLastName: values.legalLastName?.trim() ?? '',
-        phoneNumber: LoginUtils.appendCountryCode(values.phoneNumber?.trim() ?? '', countryCode),
-        addressCity: (values.city ?? '').trim(),
-        addressStreet: values.addressLine1?.trim() ?? '',
-        addressStreet2: values.addressLine2?.trim() ?? '',
-        addressZip: values.zipPostCode?.trim().toUpperCase() ?? '',
-        addressCountry: values.country ?? '',
-        addressState: stateValue,
-        addressProvince: values.country !== CONST.COUNTRY.US ? stateValue : '',
-        dob: values.dob ?? '',
-        validateCode,
-    };
-
-    API.write(WRITE_COMMANDS.UPDATE_PRIVATE_PERSONAL_DETAILS, parameters, {
-        optimisticData: [
-            {
-                onyxMethod: Onyx.METHOD.MERGE,
-                key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS,
-                value: {
-                    isLoading: true,
-                    errorFields: {personalDetails: null},
-                },
-            },
-        ],
-        successData: [
-            {
-                onyxMethod: Onyx.METHOD.MERGE,
-                key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS,
-                value: {
-                    isLoading: false,
-                },
-            },
-        ],
-        failureData: [
-            {
-                onyxMethod: Onyx.METHOD.MERGE,
-                key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS,
-                value: {
-                    isLoading: false,
-                    errorFields: {personalDetails: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')},
-                },
-            },
-        ],
     });
 }
 
@@ -608,7 +556,6 @@ export {
     clearPhoneNumberError,
     updatePronouns,
     updateSelectedTimezone,
-    updatePrivatePersonalDetails,
     updatePersonalDetailsAndShipExpensifyCards,
     clearPersonalDetailsErrors,
     buildSetPersonalDetailsAndShipExpensifyCardsParams,
diff --git a/src/pages/settings/Profile/PersonalDetails/PrivatePersonalDetailsConfirmMagicCodePage.tsx b/src/pages/settings/Profile/PersonalDetails/PrivatePersonalDetailsConfirmMagicCodePage.tsx
deleted file mode 100644
index bac67536154e..000000000000
--- a/src/pages/settings/Profile/PersonalDetails/PrivatePersonalDetailsConfirmMagicCodePage.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-import React, {useEffect, useRef} from 'react';
-import ValidateCodeActionContent from '@components/ValidateCodeActionModal/ValidateCodeActionContent';
-import useLocalize from '@hooks/useLocalize';
-import useOnyx from '@hooks/useOnyx';
-import usePrimaryContactMethod from '@hooks/usePrimaryContactMethod';
-import {clearPersonalDetailsErrors, updatePrivatePersonalDetails} from '@libs/actions/PersonalDetails';
-import {requestValidateCodeAction, resetValidateActionCodeSent} from '@libs/actions/User';
-import {normalizeCountryCode} from '@libs/CountryUtils';
-import {getLatestErrorField, getLatestErrorMessageField} from '@libs/ErrorUtils';
-import Navigation from '@libs/Navigation/Navigation';
-import {getPrivatePersonalDetailsFormValues} from '@libs/PersonalDetailsUtils';
-import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
-import ROUTES from '@src/ROUTES';
-import type {PersonalDetailsForm} from '@src/types/form';
-import {isEmptyObject} from '@src/types/utils/EmptyObject';
-
-function PrivatePersonalDetailsConfirmMagicCodePage() {
-    const {translate} = useLocalize();
-    const [privatePersonalDetails] = useOnyx(ONYXKEYS.PRIVATE_PERSONAL_DETAILS);
-    const [draftValues] = useOnyx(ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM_DRAFT);
-    const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE);
-    const primaryLogin = usePrimaryContactMethod();
-
-    const [validateCodeAction] = useOnyx(ONYXKEYS.VALIDATE_ACTION_CODE);
-
-    // Errors may be written to either errorFields (preferred) or errors depending on
-    // how the backend reports the failure, so check both.
-    const personalDetailsErrorField = getLatestErrorField(privatePersonalDetails, 'personalDetails');
-    const personalDetailsError = getLatestErrorMessageField(privatePersonalDetails);
-    const submitError = !isEmptyObject(personalDetailsErrorField) ? personalDetailsErrorField : personalDetailsError;
-    const hasErrors = !isEmptyObject(submitError) || !isEmptyObject(validateCodeAction?.errorFields);
-
-    const clearError = () => {
-        if (!hasErrors) {
-            return;
-        }
-        clearPersonalDetailsErrors();
-    };
-
-    const wasLoading = useRef(false);
-    useEffect(() => {
-        if (privatePersonalDetails?.isLoading) {
-            wasLoading.current = true;
-            return;
-        }
-        if (wasLoading.current && !hasErrors) {
-            wasLoading.current = false;
-            resetValidateActionCodeSent();
-            Navigation.goBack(ROUTES.SETTINGS_PROFILE.route);
-        }
-        wasLoading.current = false;
-    }, [privatePersonalDetails?.isLoading, hasErrors]);
-
-    const values = normalizeCountryCode(getPrivatePersonalDetailsFormValues(privatePersonalDetails, draftValues)) as PersonalDetailsForm;
-
-    const handleSubmitForm = (validateCode: string) => {
-        updatePrivatePersonalDetails(values, validateCode, countryCode);
-    };
-
-    return (
-        <ValidateCodeActionContent
-            title={translate('delegate.makeSureItIsYou')}
-            descriptionPrimary={translate('contacts.enterMagicCode', primaryLogin ?? '')}
-            sendValidateCode={() => requestValidateCodeAction()}
-            validateCodeActionErrorField="personalDetails"
-            handleSubmitForm={handleSubmitForm}
-            validateError={submitError}
-            clearError={clearError}
-            onClose={() => {
-                resetValidateActionCodeSent();
-                Navigation.goBack(ROUTES.SETTINGS_PRIVATE_PERSONAL_DETAILS.route);
-            }}
-            isLoading={privatePersonalDetails?.isLoading}
-        />
-    );
-}
-
-PrivatePersonalDetailsConfirmMagicCodePage.displayName = 'PrivatePersonalDetailsConfirmMagicCodePage';
-
-export default PrivatePersonalDetailsConfirmMagicCodePage;
diff --git a/src/pages/settings/Profile/PersonalDetails/PrivatePersonalDetailsPage.tsx b/src/pages/settings/Profile/PersonalDetails/PrivatePersonalDetailsPage.tsx
deleted file mode 100644
index eae8cdb4172f..000000000000
--- a/src/pages/settings/Profile/PersonalDetails/PrivatePersonalDetailsPage.tsx
+++ /dev/null
@@ -1,396 +0,0 @@
-import {useRoute} from '@react-navigation/native';
-import {subYears} from 'date-fns';
-import {CONST as COMMON_CONST} from 'expensify-common';
-import React, {useEffect, useState} from 'react';
-import {View} from 'react-native';
-import CountrySelector from '@components/CountrySelector';
-import DatePicker from '@components/DatePicker';
-import DelegateNoAccessWrapper from '@components/DelegateNoAccessWrapper';
-import FormProvider from '@components/Form/FormProvider';
-import InputWrapper from '@components/Form/InputWrapper';
-import type {FormInputErrors, FormOnyxValues} from '@components/Form/types';
-import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
-import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import ScreenWrapper from '@components/ScreenWrapper';
-import type {State} from '@components/StateSelector';
-import StateSelector from '@components/StateSelector';
-import Text from '@components/Text';
-import TextInput from '@components/TextInput';
-import useLocalize from '@hooks/useLocalize';
-import useOnyx from '@hooks/useOnyx';
-import useThemeStyles from '@hooks/useThemeStyles';
-import {clearDraftValues} from '@libs/actions/FormActions';
-import {normalizeCountryCode} from '@libs/CountryUtils';
-import {appendCountryCode} from '@libs/LoginUtils';
-import Navigation from '@libs/Navigation/Navigation';
-import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
-import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
-import {getCurrentAddress, getStreetLines} from '@libs/PersonalDetailsUtils';
-import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan';
-import {doesContainReservedWord, getAgeRequirementError, isRequiredFulfilled, isValidDisplayName, isValidPhoneNumber} from '@libs/ValidationUtils';
-import CONST from '@src/CONST';
-import type {Country} from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
-import ROUTES from '@src/ROUTES';
-import type SCREENS from '@src/SCREENS';
-import INPUT_IDS from '@src/types/form/PersonalDetailsForm';
-import type {Address} from '@src/types/onyx/PrivatePersonalDetails';
-
-function PrivatePersonalDetailsPage() {
-    const route = useRoute<PlatformStackRouteProp<SettingsNavigatorParamList, typeof SCREENS.SETTINGS.PROFILE.PRIVATE_PERSONAL_DETAILS>>();
-    const fieldToFocus = route.params?.fieldToFocus;
-    const [privatePersonalDetails] = useOnyx(ONYXKEYS.PRIVATE_PERSONAL_DETAILS);
-    const [isLoadingApp = true] = useOnyx(ONYXKEYS.IS_LOADING_APP);
-    const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE);
-    const styles = useThemeStyles();
-    const {translate} = useLocalize();
-
-    const legalFirstName = privatePersonalDetails?.legalFirstName ?? '';
-    const legalLastName = privatePersonalDetails?.legalLastName ?? '';
-    const phoneNumber = privatePersonalDetails?.phoneNumber ?? '';
-    const dob = privatePersonalDetails?.dob ?? '';
-    const address = normalizeCountryCode(getCurrentAddress(privatePersonalDetails)) as Address | undefined;
-    const [street1, street2Fallback] = getStreetLines(address?.street);
-    const initialStreet1 = street1 ?? '';
-    const initialStreet2 = address?.street2 ?? street2Fallback ?? '';
-    const city = address?.city ?? '';
-    const state = address?.state ?? '';
-    const zip = address?.zip ?? '';
-    const country = address?.country ?? '';
-
-    const [selectedCountry, setSelectedCountry] = useState<Country | ''>(country);
-    const [selectedState, setSelectedState] = useState(() => {
-        // If the stored state value is a full name (e.g. "California"), resolve it to a 2-letter code
-        // so the StateSelector dropdown can display it correctly.
-        if (state && !(state in COMMON_CONST.STATES)) {
-            const match = Object.entries(COMMON_CONST.STATES).find(([, v]) => v.stateName.toLowerCase() === state.toLowerCase());
-            return match ? match[0] : state;
-        }
-        return state;
-    });
-
-    useEffect(
-        () => () => {
-            clearDraftValues(ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM);
-        },
-        [],
-    );
-
-    const validate = (values: FormOnyxValues<typeof ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM>): FormInputErrors<typeof ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM> => {
-        const errors: FormInputErrors<typeof ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM> = {};
-
-        const firstNameValue = values[INPUT_IDS.LEGAL_FIRST_NAME] ?? '';
-        if (!firstNameValue.trim()) {
-            errors[INPUT_IDS.LEGAL_FIRST_NAME] = translate('common.error.fieldRequired');
-        } else if (!isValidDisplayName(firstNameValue)) {
-            errors[INPUT_IDS.LEGAL_FIRST_NAME] = translate('privatePersonalDetails.error.cannotIncludeCommaOrSemicolon');
-        } else if (firstNameValue.length > CONST.LEGAL_NAME.MAX_LENGTH) {
-            errors[INPUT_IDS.LEGAL_FIRST_NAME] = translate('common.error.characterLimitExceedCounter', firstNameValue.length, CONST.LEGAL_NAME.MAX_LENGTH);
-        } else if (doesContainReservedWord(firstNameValue, CONST.DISPLAY_NAME.RESERVED_NAMES)) {
-            errors[INPUT_IDS.LEGAL_FIRST_NAME] = translate('personalDetails.error.containsReservedWord');
-        }
-
-        const lastNameValue = values[INPUT_IDS.LEGAL_LAST_NAME] ?? '';
-        if (!lastNameValue.trim()) {
-            errors[INPUT_IDS.LEGAL_LAST_NAME] = translate('common.error.fieldRequired');
-        } else if (!isValidDisplayName(lastNameValue)) {
-            errors[INPUT_IDS.LEGAL_LAST_NAME] = translate('privatePersonalDetails.error.cannotIncludeCommaOrSemicolon');
-        } else if (lastNameValue.length > CONST.LEGAL_NAME.MAX_LENGTH) {
-            errors[INPUT_IDS.LEGAL_LAST_NAME] = translate('common.error.characterLimitExceedCounter', lastNameValue.length, CONST.LEGAL_NAME.MAX_LENGTH);
-        } else if (doesContainReservedWord(lastNameValue, CONST.DISPLAY_NAME.RESERVED_NAMES)) {
-            errors[INPUT_IDS.LEGAL_LAST_NAME] = translate('personalDetails.error.containsReservedWord');
-        }
-
-        const dobValue = values[INPUT_IDS.DATE_OF_BIRTH] ?? '';
-        if (!dobValue) {
-            errors[INPUT_IDS.DATE_OF_BIRTH] = translate('common.error.fieldRequired');
-        } else {
-            const dateError = getAgeRequirementError(translate, dobValue, CONST.DATE_BIRTH.MIN_AGE_FOR_PAYMENT, CONST.DATE_BIRTH.MAX_AGE);
-            if (dateError) {
-                errors[INPUT_IDS.DATE_OF_BIRTH] = dateError;
-            }
-        }
-
-        const phoneValue = values[INPUT_IDS.PHONE_NUMBER] ?? '';
-        if (!isRequiredFulfilled(phoneValue)) {
-            errors[INPUT_IDS.PHONE_NUMBER] = translate('common.error.fieldRequired');
-        } else {
-            const phoneWithCountryCode = appendCountryCode(phoneValue, countryCode);
-            if (!isValidPhoneNumber(phoneWithCountryCode)) {
-                errors[INPUT_IDS.PHONE_NUMBER] = translate('common.error.phoneNumber');
-            }
-        }
-
-        const streetValue = values[INPUT_IDS.ADDRESS_LINE_1] ?? '';
-        if (!streetValue.trim()) {
-            errors[INPUT_IDS.ADDRESS_LINE_1] = translate('common.error.fieldRequired');
-        }
-
-        const cityValue = values[INPUT_IDS.CITY] ?? '';
-        if (!cityValue.trim()) {
-            errors[INPUT_IDS.CITY] = translate('common.error.fieldRequired');
-        }
-
-        const stateValue = values[INPUT_IDS.STATE] || selectedState || '';
-        const effectiveCountry = (values[INPUT_IDS.COUNTRY] || selectedCountry) ?? '';
-        if (!stateValue.trim()) {
-            errors[INPUT_IDS.STATE] = translate('common.error.fieldRequired');
-        }
-
-        const zipValue = values[INPUT_IDS.ZIP_POST_CODE] ?? '';
-        const countryRegexDetails = effectiveCountry ? (CONST.COUNTRY_ZIP_REGEX_DATA?.[effectiveCountry] as {regex?: RegExp; samples?: string}) : undefined;
-        const countrySpecificZipRegex = countryRegexDetails?.regex;
-        if (countrySpecificZipRegex) {
-            if (!countrySpecificZipRegex.test(zipValue.trim().toUpperCase())) {
-                if (isRequiredFulfilled(zipValue.trim())) {
-                    errors[INPUT_IDS.ZIP_POST_CODE] = translate('privatePersonalDetails.error.incorrectZipFormat', countryRegexDetails?.samples ?? '');
-                } else {
-                    errors[INPUT_IDS.ZIP_POST_CODE] = translate('common.error.fieldRequired');
-                }
-            }
-        } else if (!CONST.GENERIC_ZIP_CODE_REGEX.test(zipValue.trim().toUpperCase())) {
-            errors[INPUT_IDS.ZIP_POST_CODE] = translate('privatePersonalDetails.error.incorrectZipFormat');
-        }
-
-        if (!effectiveCountry) {
-            errors[INPUT_IDS.COUNTRY] = translate('common.error.fieldRequired');
-        }
-
-        return errors;
-    };
-
-    const hasChanges = (values: FormOnyxValues<typeof ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM>): boolean => {
-        if ((values[INPUT_IDS.LEGAL_FIRST_NAME] ?? '') !== legalFirstName) {
-            return true;
-        }
-        if ((values[INPUT_IDS.LEGAL_LAST_NAME] ?? '') !== legalLastName) {
-            return true;
-        }
-        if ((values[INPUT_IDS.DATE_OF_BIRTH] ?? '') !== dob) {
-            return true;
-        }
-        if ((values[INPUT_IDS.PHONE_NUMBER] ?? '') !== phoneNumber) {
-            return true;
-        }
-        if ((values[INPUT_IDS.ADDRESS_LINE_1] ?? '') !== initialStreet1) {
-            return true;
-        }
-        if ((values[INPUT_IDS.ADDRESS_LINE_2] ?? '') !== initialStreet2) {
-            return true;
-        }
-        if ((values[INPUT_IDS.CITY] ?? '') !== city) {
-            return true;
-        }
-        if ((values[INPUT_IDS.STATE] ?? '') !== state) {
-            return true;
-        }
-        if ((values[INPUT_IDS.ZIP_POST_CODE] ?? '') !== zip) {
-            return true;
-        }
-        if ((values[INPUT_IDS.COUNTRY] ?? '') !== country) {
-            return true;
-        }
-        return false;
-    };
-
-    const onSubmit = (values: FormOnyxValues<typeof ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM>) => {
-        if (!hasChanges(values)) {
-            Navigation.goBack();
-            return;
-        }
-        Navigation.navigate(ROUTES.SETTINGS_PRIVATE_PERSONAL_DETAILS_CONFIRM_MAGIC_CODE);
-    };
-
-    const reasonAttributes: SkeletonSpanReasonAttributes = {context: 'PrivatePersonalDetailsPage', isLoadingApp};
-
-    if (isLoadingApp) {
-        return (
-            <FullScreenLoadingIndicator
-                reasonAttributes={reasonAttributes}
-                shouldUseGoBackButton
-            />
-        );
-    }
-
-    return (
-        <ScreenWrapper
-            includeSafeAreaPaddingBottom
-            testID="PrivatePersonalDetailsPage"
-        >
-            <DelegateNoAccessWrapper accessDeniedVariants={[CONST.DELEGATE.DENIED_ACCESS_VARIANTS.DELEGATE]}>
-                <HeaderWithBackButton
-                    title={translate('privatePersonalDetails.personalDetails')}
-                    onBackButtonPress={() => Navigation.goBack()}
-                />
-                <FormProvider
-                    style={[styles.flexGrow1, styles.ph5]}
-                    formID={ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM}
-                    validate={validate}
-                    onSubmit={onSubmit}
-                    submitButtonText={translate('common.save')}
-                    enabledWhenOffline
-                >
-                    <Text style={[styles.textStrong, styles.mb2]}>{translate('privatePersonalDetails.basicDetails')}</Text>
-                    <View style={styles.mb4}>
-                        <InputWrapper
-                            InputComponent={TextInput}
-                            inputID={INPUT_IDS.LEGAL_FIRST_NAME}
-                            label={translate('privatePersonalDetails.legalFirstName')}
-                            aria-label={translate('privatePersonalDetails.legalFirstName')}
-                            role={CONST.ROLE.PRESENTATION}
-                            defaultValue={legalFirstName}
-                            shouldSaveDraft
-                            spellCheck={false}
-                            autoCapitalize="words"
-                            autoComplete="given-name"
-                            autoFocus={fieldToFocus === INPUT_IDS.LEGAL_FIRST_NAME}
-                        />
-                    </View>
-                    <View style={styles.mb4}>
-                        <InputWrapper
-                            InputComponent={TextInput}
-                            inputID={INPUT_IDS.LEGAL_LAST_NAME}
-                            label={translate('privatePersonalDetails.legalLastName')}
-                            aria-label={translate('privatePersonalDetails.legalLastName')}
-                            role={CONST.ROLE.PRESENTATION}
-                            defaultValue={legalLastName}
-                            shouldSaveDraft
-                            spellCheck={false}
-                            autoCapitalize="words"
-                            autoComplete="family-name"
-                            autoFocus={fieldToFocus === INPUT_IDS.LEGAL_LAST_NAME}
-                        />
-                    </View>
-                    <View style={styles.mb4}>
-                        <InputWrapper
-                            InputComponent={DatePicker}
-                            inputID={INPUT_IDS.DATE_OF_BIRTH}
-                            label={translate('common.date')}
-                            defaultValue={dob}
-                            shouldSaveDraft
-                            minDate={subYears(new Date(), CONST.DATE_BIRTH.MAX_AGE)}
-                            maxDate={subYears(new Date(), CONST.DATE_BIRTH.MIN_AGE_FOR_PAYMENT)}
-                            autoComplete="birthdate-full"
-                            autoFocus={fieldToFocus === INPUT_IDS.DATE_OF_BIRTH}
-                        />
-                    </View>
-                    <View style={styles.mb4}>
-                        <InputWrapper
-                            InputComponent={TextInput}
-                            inputID={INPUT_IDS.PHONE_NUMBER}
-                            label={translate('common.phoneNumber')}
-                            aria-label={translate('common.phoneNumber')}
-                            role={CONST.ROLE.PRESENTATION}
-                            defaultValue={phoneNumber}
-                            shouldSaveDraft
-                            spellCheck={false}
-                            inputMode={CONST.INPUT_MODE.TEL}
-                            autoComplete="tel"
-                            autoFocus={fieldToFocus === INPUT_IDS.PHONE_NUMBER}
-                        />
-                    </View>
-                    <Text style={[styles.textStrong, styles.mb2]}>{translate('privatePersonalDetails.address')}</Text>
-                    <View style={styles.mb4}>
-                        <InputWrapper
-                            InputComponent={TextInput}
-                            inputID={INPUT_IDS.ADDRESS_LINE_1}
-                            label={translate('common.addressLine', 1)}
-                            aria-label={translate('common.addressLine', 1)}
-                            role={CONST.ROLE.PRESENTATION}
-                            defaultValue={initialStreet1}
-                            shouldSaveDraft
-                            spellCheck={false}
-                            autoComplete="address-line1"
-                            autoFocus={fieldToFocus === INPUT_IDS.ADDRESS_LINE_1}
-                        />
-                    </View>
-                    <View style={styles.mb4}>
-                        <InputWrapper
-                            InputComponent={TextInput}
-                            inputID={INPUT_IDS.ADDRESS_LINE_2}
-                            label={translate('common.addressLine', 2)}
-                            aria-label={translate('common.addressLine', 2)}
-                            role={CONST.ROLE.PRESENTATION}
-                            defaultValue={initialStreet2}
-                            shouldSaveDraft
-                            spellCheck={false}
-                            autoComplete="address-line2"
-                        />
-                    </View>
-                    <View style={styles.mb4}>
-                        <InputWrapper
-                            InputComponent={TextInput}
-                            inputID={INPUT_IDS.CITY}
-                            label={translate('common.city')}
-                            aria-label={translate('common.city')}
-                            role={CONST.ROLE.PRESENTATION}
-                            defaultValue={city}
-                            shouldSaveDraft
-                            spellCheck={false}
-                            autoComplete="street-address"
-                        />
-                    </View>
-                    {selectedCountry === CONST.COUNTRY.US ? (
-                        <View style={[styles.mhn5, styles.mb4]}>
-                            <InputWrapper
-                                InputComponent={StateSelector}
-                                inputID={INPUT_IDS.STATE}
-                                value={selectedState as State}
-                                onValueChange={(value: unknown) => setSelectedState((value ?? '') as string)}
-                                shouldSaveDraft
-                            />
-                        </View>
-                    ) : (
-                        <View style={styles.mb4}>
-                            <InputWrapper
-                                InputComponent={TextInput}
-                                inputID={INPUT_IDS.STATE}
-                                label={translate('common.stateOrProvince')}
-                                aria-label={translate('common.stateOrProvince')}
-                                role={CONST.ROLE.PRESENTATION}
-                                defaultValue={state}
-                                shouldSaveDraft
-                                spellCheck={false}
-                            />
-                        </View>
-                    )}
-                    <View style={styles.mb4}>
-                        <InputWrapper
-                            InputComponent={TextInput}
-                            inputID={INPUT_IDS.ZIP_POST_CODE}
-                            label={translate('common.zipPostCode')}
-                            aria-label={translate('common.zipPostCode')}
-                            role={CONST.ROLE.PRESENTATION}
-                            defaultValue={zip}
-                            shouldSaveDraft
-                            spellCheck={false}
-                            autoComplete="postal-code"
-                        />
-                    </View>
-                    <View style={styles.mhn5}>
-                        <InputWrapper
-                            InputComponent={CountrySelector}
-                            inputID={INPUT_IDS.COUNTRY}
-                            value={selectedCountry}
-                            onValueChange={(value: unknown) => {
-                                const newCountry = (value ?? '') as Country | '';
-                                setSelectedCountry(newCountry);
-                                if (newCountry === CONST.COUNTRY.US && selectedState && !(selectedState in COMMON_CONST.STATES)) {
-                                    const match = Object.entries(COMMON_CONST.STATES).find(([, v]) => v.stateName.toLowerCase() === selectedState.toLowerCase());
-                                    if (match) {
-                                        setSelectedState(match[0]);
-                                    }
-                                }
-                            }}
-                            shouldSaveDraft
-                        />
-                    </View>
-                </FormProvider>
-            </DelegateNoAccessWrapper>
-        </ScreenWrapper>
-    );
-}
-
-PrivatePersonalDetailsPage.displayName = 'PrivatePersonalDetailsPage';
-
-export default PrivatePersonalDetailsPage;
