Skip to content

feat(dev-portal-web): INFRA-1712 media upload global refactoring#7787

Merged
SavelevMatthew merged 8 commits into
mainfrom
feat/INFRA-1712/icons
Jun 24, 2026
Merged

feat(dev-portal-web): INFRA-1712 media upload global refactoring#7787
SavelevMatthew merged 8 commits into
mainfrom
feat/INFRA-1712/icons

Conversation

@SavelevMatthew

@SavelevMatthew SavelevMatthew commented Jun 24, 2026

Copy link
Copy Markdown
Member
Screen.Recording.2026-06-24.at.17.04.29.mov

Summary by CodeRabbit

  • New Features
    • Added a new “Media” section for B2B app editing, including logo upload, preview, and save.
    • Introduced a reusable media upload experience with restrictions, preview, and guide/warning UI.
  • Bug Fixes
    • Improved markdown length validation by safely handling non-string inputs.
  • Refactor
    • Updated B2C app icons editing to use the shared media upload experience.
  • Style / Localization
    • Added/updated English and Russian strings for the new media upload and icons/media sections.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7e0bcd5e-f62d-42c7-baff-555cbb6535ef

📥 Commits

Reviewing files that changed from the base of the PR and between a372200 and f46a415.

📒 Files selected for processing (5)
  • apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/MediaSubsection.tsx
  • apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx
  • apps/dev-portal-web/domains/miniapp/components/MediaUpload.tsx
  • apps/dev-portal-web/lang/en.json
  • apps/dev-portal-web/lang/ru.json
✅ Files skipped from review due to trivial changes (1)
  • apps/dev-portal-web/lang/en.json
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/dev-portal-web/domains/miniapp/components/MediaUpload.tsx
  • apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/MediaSubsection.tsx
  • apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx
  • apps/dev-portal-web/lang/ru.json

📝 Walkthrough

Walkthrough

Adds a shared media upload component, wires it into a new B2B media subsection, refactors the B2C icons section to use the shared flow, and updates related constants, translations, and markdown validation.

Changes

MediaUpload feature: shared component, B2B logo upload, B2C refactor

Layer / File(s) Summary
Shared MediaUpload component
apps/dev-portal-web/domains/miniapp/components/MediaUpload.tsx, apps/dev-portal-web/domains/miniapp/components/MediaUpload.module.css
Defines upload restriction and save types, adds clipboard color-chip behavior, manages file validation and preview object URLs, and renders the upload form with restrictions, guide link, warning area, and submit action. The stylesheet provides the layout classes used by the component.
B2B media subsection and preview card
apps/dev-portal-web/domains/miniapp/constants/common.ts, apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/B2BAppCard.tsx, apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/B2BAppCard.module.css, apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/MediaSubsection.tsx, apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/index.ts, apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/InfoSection.tsx
Adds B2B logo constants, a preview card, subsection styling, the upload-and-mutate flow for saving the app logo, a re-export, and the InfoSection insertion for the new media subsection.
B2C icons subsection refactor
apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx
Replaces the inline Form/Upload UI with MediaUpload, updates the save handler to accept uploaded files, and passes preview, restriction, warning, and guide props into the shared component.
Localization and validation updates
apps/dev-portal-web/lang/en.json, apps/dev-portal-web/lang/ru.json, apps/dev-portal-web/domains/common/hooks/useMarkdownLengthValidation.ts
Adds and updates translation keys for media upload labels, B2B media text, and B2C icon copy, and adds a non-string guard to the markdown length validator.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant MediaUpload
  participant MediaSubsection
  participant uploadFiles as uploadFiles(`@open-condo/files`)
  participant useUpdateB2BAppMutation
  participant GetB2BAppDocument

  User->>MediaUpload: selects logo file
  MediaUpload->>MediaUpload: validate and build preview
  User->>MediaUpload: clicks Save
  MediaUpload->>MediaSubsection: onSave(uploadedFiles)
  MediaSubsection->>uploadFiles: upload with sender/user/model/item metadata
  uploadFiles-->>MediaSubsection: UploadFileResult[]
  MediaSubsection->>useUpdateB2BAppMutation: set logo field
  useUpdateB2BAppMutation->>GetB2BAppDocument: refetchQueries(id)
  GetB2BAppDocument-->>MediaSubsection: updated app data
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • open-condo-software/condo#7742: Both PRs modify apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx and the upload/save flow around app icon handling.

🐇 I hopped through uploads and shiny new views,
With media cards and tiny color clues.
B2B got a fresh icon nest,
B2C now rides the shared-path quest.
One hop, one save, one tidy stream—
and translations glint like a moonlit beam.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: a dev-portal-web media upload refactor.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/INFRA-1712/icons

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 OpenGrep (1.23.0)
apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

[00.16][ERROR]: unable to find a config; path .coderabbit-opengrep-fallback.yml does not exist

apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/MediaSubsection.tsx

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

[00.21][ERROR]: unable to find a config; path .coderabbit-opengrep-fallback.yml does not exist

apps/dev-portal-web/domains/miniapp/components/MediaUpload.tsx

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

[00.21][ERROR]: unable to find a config; path .coderabbit-opengrep-fallback.yml does not exist

  • 2 others
🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ec65375de1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


const handleSave = useCallback(async () => {
await onSave?.(currentFiles)
setCurrentFiles([])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep the selected file when saving fails

If uploadFiles fails, the B2B/B2C save handlers catch the exception, call onError, and return without throwing, but MediaUpload still clears currentFiles and the preview immediately after onSave returns. In a transient upload/server error the error notification is shown and the chosen file disappears, so the user cannot retry Save without reselecting it; reset this state only after a confirmed successful save or make onSave signal failure.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good one, will fix it

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx (1)

53-70: 🩺 Stability & Availability | 🟡 Minor

Drop the disconnected form instance. IconsSubsection no longer renders a <Form>, while MediaUpload manages its own internal form/state, so form.resetFields() is redundant and can be removed along with the unused Form import.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx`
around lines 53 - 70, IconsSubsection still creates a disconnected Ant Design
form instance even though it no longer renders a Form and MediaUpload manages
its own state. Remove the unused Form.useForm setup and the form.resetFields()
call from the onCompleted callback, and clean up the now-unused Form import
while keeping useMutationCompletedHandler and useUpdateB2CAppMutation behavior
unchanged.
🧹 Nitpick comments (2)
apps/dev-portal-web/domains/miniapp/components/MediaUpload.tsx (1)

17-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

mimetypes literal restriction collapses to string.

Because ALLOWED_MIMETYPES is not declared as const, typeof ALLOWED_MIMETYPES[number] resolves to string, so MediaRestrictions.mimetypes accepts any string rather than the intended 'image/webp' | 'image/png' union. Add as const to preserve the literals.

♻️ Suggested change
-const ALLOWED_MIMETYPES = ['image/webp', 'image/png']
+const ALLOWED_MIMETYPES = ['image/webp', 'image/png'] as const

Also applies to: 22-23

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/dev-portal-web/domains/miniapp/components/MediaUpload.tsx` at line 17,
Add as const to ALLOWED_MIMETYPES in MediaUpload so typeof
ALLOWED_MIMETYPES[number] preserves the literal union instead of widening to
string, and keep MediaRestrictions.mimetypes typed from that constant so it only
accepts the intended image/webp and image/png values. Update the
ALLOWED_MIMETYPES definition and any related type usage in MediaUpload to rely
on the narrowed tuple type.
apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx (1)

72-101: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid shadowing the uploadedFiles parameter.

The SaveHandler parameter uploadedFiles (Line 72) is shadowed by the destructured result of uploadFiles on Line 80 (const { files: uploadedFiles } = ...). This is confusing to read and obscures which value is in scope below. Rename the inner binding.

♻️ Suggested rename
-            const { files: uploadedFiles } = await uploadFiles({
+            const { files: resultFiles } = await uploadFiles({
                 ...
             })
-            files = uploadedFiles
+            files = resultFiles
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx`
around lines 72 - 101, The SaveHandler in IconsSubsection’s handleIconSave is
shadowing its uploadedFiles parameter with the destructured uploadFiles result,
which makes the scope confusing. Rename the inner binding from uploadFiles to a
distinct name (for example, uploadedResultFiles) and keep the rest of the logic
in handleIconSave unchanged so it’s clear which files array is being referenced.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/MediaSubsection.tsx`:
- Around line 1-20: The import block in MediaSubsection should be reordered to
match the enforced grouped order and alphabetical sorting. Update the imports in
MediaSubsection.tsx so external, `@open-condo`, internal, and sibling imports are
grouped correctly, and move
GetB2BAppDocument/useGetB2BAppQuery/useUpdateB2BAppMutation into the proper
internal group without leaving an external import after internal/sibling
imports.

In `@apps/dev-portal-web/domains/miniapp/components/MediaUpload.tsx`:
- Around line 114-120: The color separator logic in MediaUpload’s ColorsValue
memo is inverted, so lists with 3+ items render incorrectly. Update the flatMap
in ColorsValue so the separator is added before every non-first ColorSpan (idx
!== 0) rather than after the first item, keeping the existing ColorSpan and
styles.colon usage intact.
- Around line 122-139: Object URLs created in MediaUpload are only revoked
during file change and save, so they can leak if the component unmounts while
previews are still active. Add an unmount cleanup in MediaUpload using useEffect
to revoke every previewUrl currently stored in previewState, and update the
React import to include useEffect; keep the existing cleanup behavior in
handleFileChange and handleSave, and reference the handleFileChange, handleSave,
and previewState logic when making the change.

In `@apps/dev-portal-web/lang/en.json`:
- Line 298: The user-facing copy in the localization entry for
pages.apps.b2c.id.sections.info.icons.items.main.description has a grammar
mistake with an extra “in”; update the string to remove the stray word so it
reads naturally. Keep the change limited to that translation key in en.json and
verify the revised wording still clearly describes that it is used to display on
the resident’s home screen in the mobile and web apps.

In `@apps/dev-portal-web/lang/ru.json`:
- Line 300: The Russian translation for
pages.apps.b2c.id.sections.info.icons.items.main.description contains a
grammatical typo with an extra “в” before “для”; update the string in ru.json to
use the correct phrasing, keeping the meaning intact while fixing the malformed
Russian wording.

---

Outside diff comments:
In
`@apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx`:
- Around line 53-70: IconsSubsection still creates a disconnected Ant Design
form instance even though it no longer renders a Form and MediaUpload manages
its own state. Remove the unused Form.useForm setup and the form.resetFields()
call from the onCompleted callback, and clean up the now-unused Form import
while keeping useMutationCompletedHandler and useUpdateB2CAppMutation behavior
unchanged.

---

Nitpick comments:
In
`@apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx`:
- Around line 72-101: The SaveHandler in IconsSubsection’s handleIconSave is
shadowing its uploadedFiles parameter with the destructured uploadFiles result,
which makes the scope confusing. Rename the inner binding from uploadFiles to a
distinct name (for example, uploadedResultFiles) and keep the rest of the logic
in handleIconSave unchanged so it’s clear which files array is being referenced.

In `@apps/dev-portal-web/domains/miniapp/components/MediaUpload.tsx`:
- Line 17: Add as const to ALLOWED_MIMETYPES in MediaUpload so typeof
ALLOWED_MIMETYPES[number] preserves the literal union instead of widening to
string, and keep MediaRestrictions.mimetypes typed from that constant so it only
accepts the intended image/webp and image/png values. Update the
ALLOWED_MIMETYPES definition and any related type usage in MediaUpload to rely
on the narrowed tuple type.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b566226f-46b3-4a87-8826-e72d4de76967

📥 Commits

Reviewing files that changed from the base of the PR and between dc24678 and ec65375.

⛔ Files ignored due to path filters (1)
  • apps/dev-portal-web/public/icons/b2b.png is excluded by !**/*.png
📒 Files selected for processing (12)
  • apps/dev-portal-web/domains/common/hooks/useMarkdownLengthValidation.ts
  • apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/InfoSection.tsx
  • apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/B2BAppCard.module.css
  • apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/B2BAppCard.tsx
  • apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/MediaSubsection.tsx
  • apps/dev-portal-web/domains/miniapp/components/B2BApp/edit/info/MediaSubsection/index.ts
  • apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.module.css
  • apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.tsx
  • apps/dev-portal-web/domains/miniapp/components/MediaUpload.module.css
  • apps/dev-portal-web/domains/miniapp/components/MediaUpload.tsx
  • apps/dev-portal-web/lang/en.json
  • apps/dev-portal-web/lang/ru.json
💤 Files with no reviewable changes (1)
  • apps/dev-portal-web/domains/miniapp/components/B2CApp/edit/info/IconsSubsection.module.css

Comment thread apps/dev-portal-web/domains/miniapp/components/MediaUpload.tsx
Comment thread apps/dev-portal-web/domains/miniapp/components/MediaUpload.tsx
Comment thread apps/dev-portal-web/lang/en.json Outdated
Comment thread apps/dev-portal-web/lang/ru.json Outdated
@SavelevMatthew SavelevMatthew merged commit b4231a4 into main Jun 24, 2026
42 of 44 checks passed
@SavelevMatthew SavelevMatthew deleted the feat/INFRA-1712/icons branch June 24, 2026 17:22
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
8.2% Duplication on New Code (required ≤ 3%)
B Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant