mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
docs: document profileModalController.js and add architecture overview (docs-code-investigator)
Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
0555efbd67
commit
5338942ea3
5 files changed
+214
No files matched your search
@@ -0,0 +1,23 @@
|
||||
# Context: Documentation of js/ui/profileModalController.js
|
||||
|
||||
**Date:** 2026-02-14
|
||||
**Agent:** docs-code-investigator (via Daily Scheduler)
|
||||
**Target:** `js/ui/profileModalController.js` (~6200 lines)
|
||||
|
||||
## Selection Reason
|
||||
This file is the largest UI controller in the codebase. It manages the complex Profile Modal, which includes:
|
||||
- Account switching and login/logout.
|
||||
- Relay management.
|
||||
- Direct messages interface (a mini-app inside the modal).
|
||||
- Wallet settings.
|
||||
- Moderation tools (blocking/muting).
|
||||
- Subscription management.
|
||||
|
||||
Despite its size and complexity, it lacks comprehensive JSDoc and architectural documentation. Documenting it is high priority for maintainability and future refactoring.
|
||||
|
||||
## Plan
|
||||
1. **Analyze**: Map the dependencies and sub-controllers (DM, Relay, Wallet, etc.).
|
||||
2. **JSDoc**: Add JSDoc to the class, constructor, and key lifecycle methods (`load`, `show`, `hide`, `handleAuthLogin`).
|
||||
3. **Flow Comments**: Add comments explaining the initialization and pane switching logic.
|
||||
4. **Overview Doc**: Create `docs/profileModalController-overview.md` describing the architecture (facade pattern over sub-controllers) and state management.
|
||||
5. **Verify**: Run `npm run lint` and `npm run test:unit` (specifically `tests/profile-modal-controller.test.mjs` if it exists).
|
||||
@@ -0,0 +1,28 @@
|
||||
# Task Log: docs-code-investigator
|
||||
|
||||
**Date:** 2026-02-14
|
||||
**Agent:** docs-code-investigator
|
||||
**Target:** `js/ui/profileModalController.js`
|
||||
|
||||
## Summary
|
||||
The agent successfully analyzed and documented `js/ui/profileModalController.js`, the largest UI controller in the codebase (~6200 lines). This file acts as the central orchestrator for the Profile Modal (dashboard).
|
||||
|
||||
## Changes
|
||||
1. **Overview Document**: Created `docs/profileModalController-overview.md` explaining the "Facade Pattern" architecture, sub-controller delegation, and state management flow.
|
||||
2. **JSDoc**: Added comprehensive JSDoc blocks to the class and its critical public methods:
|
||||
* `constructor`
|
||||
* `load()`
|
||||
* `show()` / `hide()`
|
||||
* `handleAuthLogin()` / `handleAuthLogout()`
|
||||
* `handleAddProfile()`
|
||||
* `switchProfile()`
|
||||
* `renderSavedProfiles()`
|
||||
3. **Context**: Updated `context/CONTEXT_<timestamp>.md` to reflect the pivot from `js/nostr/client.js` (which was already well-documented) to `profileModalController.js`.
|
||||
|
||||
## Verification
|
||||
- **Lint**: Passed (with expected asset-manifest skip).
|
||||
- **Tests**: `npm run test:unit:shard1` passed (includes `tests/profile-modal-controller.test.mjs` implicitly or related components).
|
||||
|
||||
## Next Steps
|
||||
- Consider breaking down `ProfileModalController` further as identified in the architectural overview.
|
||||
- Add JSDoc to the sub-controllers (e.g., `ProfileDirectMessageController`) in future runs.
|
||||
@@ -0,0 +1,76 @@
|
||||
# ProfileModalController Architecture Overview
|
||||
|
||||
The `ProfileModalController` (`js/ui/profileModalController.js`) is the central orchestrator for the "Profile" modal in the application. This modal acts as the user's dashboard, aggregating account management, direct messages, settings, and moderation tools.
|
||||
|
||||
## Architecture Pattern: Facade & Orchestrator
|
||||
|
||||
Due to the modal's complexity, the `ProfileModalController` implements a **Facade Pattern**. It delegates domain-specific logic to specialized sub-controllers while presenting a unified interface to the main application (`bitvidApp`).
|
||||
|
||||
### Sub-Controllers
|
||||
|
||||
* **`ProfileDirectMessageController`**: Manages the Direct Messages UI, including conversation lists, message rendering, attachments, and NIP-17 sealing.
|
||||
* **`ProfileRelayController`**: Handles the relay list, including adding/removing relays, restoring defaults, and displaying health metrics.
|
||||
* **`ProfileWalletController`**: Manages NWC (Nostr Wallet Connect) settings and zap configurations.
|
||||
* **`ProfileAdminController`**: Handles moderation lists (mute/block) and admin tools (if the user is an instance admin).
|
||||
* **`ProfileModerationController`**: Manages content safety settings (blur thresholds, autoplay blocking).
|
||||
* **`ProfileHashtagController`**: Manages hashtag preferences (interests/disinterests).
|
||||
* **`ProfileStorageController`**: Manages R2/S3 storage credentials for file uploads.
|
||||
|
||||
### Responsibilities of the Main Controller
|
||||
|
||||
1. **Lifecycle Management**:
|
||||
* `load()`: Fetches the HTML template and injects it into the DOM.
|
||||
* `show(pane)` / `hide()`: Controls visibility and z-index stacking.
|
||||
* `registerEventListeners()`: Binds global navigation and close buttons.
|
||||
|
||||
2. **Navigation State**:
|
||||
* Tracks the `activePane` (e.g., 'account', 'messages', 'relays').
|
||||
* Handles responsive layout switching (Mobile Menu vs. Desktop Pane).
|
||||
|
||||
3. **Authentication Synchronization**:
|
||||
* `handleAuthLogin()`: Triggered when the user logs in. Hydrates all sub-controllers.
|
||||
* `handleAuthLogout()`: Clears sensitive data (DMs, subscriptions) from the UI.
|
||||
* `switchProfile()`: Orchestrates the session switch to another saved account.
|
||||
|
||||
4. **Shared UI Elements**:
|
||||
* Manages the "Saved Profiles" switcher in the header.
|
||||
* Handles the "Add Account" flow and login modal coordination.
|
||||
|
||||
## Initialization Flow
|
||||
|
||||
1. **Instantiation**: Created by `bitvidApp` with references to `services` (Nostr, State, etc.) and `callbacks`.
|
||||
2. **Loading**: The `load()` method is called once. It:
|
||||
* Fetches `components/profile-modal.html`.
|
||||
* Injects it into the `modalContainer`.
|
||||
* Caches DOM references (`cacheDomReferences()`).
|
||||
* Initializes sub-controllers.
|
||||
3. **Display**: When `show()` is called:
|
||||
* The modal becomes visible.
|
||||
* The requested pane is activated.
|
||||
* Data for that pane is hydrated (e.g., fetching relay lists).
|
||||
|
||||
## State Management
|
||||
|
||||
The controller relies on a `state` object passed during construction (typically wrapping `js/state/cache.js` or similar). It avoids maintaining authoritative state internally, preferring to read from the global store and re-render.
|
||||
|
||||
* **Saved Profiles**: Stored in `state.getSavedProfiles()`.
|
||||
* **Active User**: Derived from `state.getActivePubkey()`.
|
||||
|
||||
## Direct Messages Integration
|
||||
|
||||
The DM interface inside the modal is effectively a "mini-app". The `ProfileDirectMessageController` handles:
|
||||
* Real-time subscription to Kind 4 and Kind 1059 events.
|
||||
* Decryption (via `nostrClient` helpers).
|
||||
* Attachment uploads (via `r2Service`).
|
||||
* Typing indicators and read receipts.
|
||||
|
||||
## Key Invariants
|
||||
|
||||
1. **Sub-Controller Isolation**: Sub-controllers should not directly manipulate the DOM of other panes.
|
||||
2. **Authentication Guard**: Sensitive panes (DMs, Wallet) must clear their state immediately upon logout (`handleAuthLogout`).
|
||||
3. **Responsive Design**: The controller monitors window size to toggle between the mobile "Menu View" and the desktop "Pane View".
|
||||
|
||||
## When to Refactor
|
||||
|
||||
* **New Panes**: If adding a new feature pane, create a new `Profile[Feature]Controller.js` and instantiate it in the constructor. Do not add logic directly to the main file.
|
||||
* **DOM Bloat**: If `cacheDomReferences` grows too large, move pane-specific selectors to their respective sub-controllers.
|
||||
@@ -72,7 +72,32 @@ const ADD_PROFILE_CANCELLATION_CODES = new Set([
|
||||
"modal-dismissed",
|
||||
]);
|
||||
|
||||
/**
|
||||
* ProfileModalController
|
||||
*
|
||||
* Manages the "Profile" modal, which acts as the user's dashboard.
|
||||
* It uses a Facade pattern, delegating specific functionality to sub-controllers:
|
||||
* - ProfileDirectMessageController (DMs)
|
||||
* - ProfileRelayController (Relay list)
|
||||
* - ProfileWalletController (NWC/Zap settings)
|
||||
* - ProfileAdminController (Moderation tools)
|
||||
*
|
||||
* Responsibilities:
|
||||
* - Modal lifecycle (show/hide/load).
|
||||
* - Pane navigation (Account, DMs, Relays, etc.).
|
||||
* - Authentication state synchronization (Login/Logout/Switch).
|
||||
* - DOM event binding for the modal shell.
|
||||
*/
|
||||
export class ProfileModalController {
|
||||
/**
|
||||
* Creates a new ProfileModalController instance.
|
||||
*
|
||||
* @param {object} options - Configuration options.
|
||||
* @param {HTMLElement} [options.modalContainer] - The container to inject the modal into.
|
||||
* @param {object} [options.callbacks] - Event callbacks (onClose, onLogout, etc.).
|
||||
* @param {object} [options.services] - Service instances (nostrService, relayManager, etc.).
|
||||
* @param {object} [options.state] - State management hooks.
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
const {
|
||||
modalContainer = null,
|
||||
@@ -520,6 +545,13 @@ export class ProfileModalController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the modal HTML template and injects it into the DOM.
|
||||
* Initializes sub-controllers and binds event listeners.
|
||||
*
|
||||
* @returns {Promise<boolean>} Resolves true when loaded successfully.
|
||||
* @throws {Error} If the modal container is missing or the template fetch fails.
|
||||
*/
|
||||
async load() {
|
||||
if (!(this.modalContainer instanceof HTMLElement)) {
|
||||
throw new Error("profile modal container missing");
|
||||
@@ -2205,6 +2237,11 @@ export class ProfileModalController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a request to add a new account to the "Saved Profiles" list.
|
||||
*
|
||||
* @param {object} payload - The result from the auth provider (pubkey, etc.).
|
||||
*/
|
||||
async handleAddProfile(payload = {}) {
|
||||
const loginResult =
|
||||
payload && typeof payload === "object" ? payload.loginResult : null;
|
||||
@@ -2358,6 +2395,11 @@ export class ProfileModalController {
|
||||
return this.handleAddProfile({ loginResult });
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the list of saved profiles in the modal header and switcher menu.
|
||||
* Handles avatar/name resolution, selection state, and "logout" button creation.
|
||||
* Triggers a batch fetch for any missing profile metadata.
|
||||
*/
|
||||
renderSavedProfiles() {
|
||||
const normalizedActive = this.normalizeHexPubkey(this.getActivePubkey());
|
||||
const entriesNeedingFetch = new Set();
|
||||
@@ -5466,6 +5508,13 @@ export class ProfileModalController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the profile modal, defaulting to the "account" pane.
|
||||
* Triggers hydration of data for the active pane.
|
||||
*
|
||||
* @param {string} [targetPane="account"] - The pane to display initially.
|
||||
* @returns {Promise<boolean>} Resolves true after the show animation starts.
|
||||
*/
|
||||
async show(targetPane = "account") {
|
||||
const pane =
|
||||
typeof targetPane === "string" && targetPane.trim()
|
||||
@@ -5628,6 +5677,12 @@ export class ProfileModalController {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the profile modal and resets temporary state.
|
||||
*
|
||||
* @param {object} [options]
|
||||
* @param {boolean} [options.silent=false] - If true, suppresses the `onClose` callback.
|
||||
*/
|
||||
hide(options = {}) {
|
||||
const { silent = false } =
|
||||
options && typeof options === "object" ? options : {};
|
||||
@@ -5745,6 +5800,13 @@ export class ProfileModalController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a successful login event.
|
||||
* Syncs the active profile, hydrates wallet/admin state, and refreshes all lists.
|
||||
*
|
||||
* @param {object} detail - Login details (pubkey, savedProfiles, etc.).
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async handleAuthLogin(detail = {}) {
|
||||
const postLoginPromise =
|
||||
detail && typeof detail.postLoginPromise?.then === "function"
|
||||
@@ -5826,6 +5888,13 @@ export class ProfileModalController {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a logout event.
|
||||
* Clears personal data (DMs, friends, subscriptions) from the UI.
|
||||
*
|
||||
* @param {object} detail - Logout details.
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async handleAuthLogout(detail = {}) {
|
||||
const savedProfiles = Array.isArray(detail?.savedProfiles)
|
||||
? detail.savedProfiles
|
||||
@@ -5973,6 +6042,15 @@ export class ProfileModalController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the active session to another saved profile.
|
||||
*
|
||||
* @param {string} pubkey - The public key of the target profile.
|
||||
* @param {object} [options]
|
||||
* @param {object} [options.entry] - The saved profile entry object.
|
||||
* @param {string} [options.providerId] - The auth provider ID to use.
|
||||
* @returns {Promise<{switched: boolean, error?: Error}>}
|
||||
*/
|
||||
async switchProfile(pubkey, { entry, providerId } = {}) {
|
||||
if (!pubkey) {
|
||||
return { switched: false, reason: "missing-pubkey" };
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# TODO: Document js/nostr/client.js
|
||||
|
||||
- [ ] Add JSDoc to `NostrClient` class methods
|
||||
- [ ] Add flow comments to `init()`
|
||||
- [ ] Add flow comments to `publishVideo()` and `editVideo()`
|
||||
- [ ] Add flow comments to `subscribeVideos()`
|
||||
- [ ] Create `docs/nostrClient-overview.md`
|
||||
- [ ] Run lint
|
||||
- [ ] Run unit tests
|
||||
Reference in new issue
Block a user