Extend User Profile with Bio, Social Links, and Expertise Tags#151
Extend User Profile with Bio, Social Links, and Expertise Tags#151pheobeayo wants to merge 2 commits intoInferara:mainfrom
Conversation
|
hi @pheobeayo please make sure you meet all the requirements listed in #70 when submitting a PR. Most importantly is the note on a short demo walkthrough of changes. No audio or personal identifying info is required, just a simple video showing the changes. |
Demo video added |
There was a problem hiding this comment.
Pull request overview
Extends the regular user profile UX to support richer profile metadata (social links + expertise tags) and adds shared validation/constants for the new profile fields.
Changes:
- Added social link fields (website, Twitter/X, GitHub, Discord) to the edit form and rendered social icon links on the profile page.
- Added expertise tags with predefined autocomplete + free-form entry, and displayed tags as chips on the profile.
- Introduced shared constants/validators (
MAX_BIO_LENGTH, tag limits, URL validation helpers) and small UI helpers (character counter, tags input).
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| UI/src/features/pages/regular/profile/profile.tsx | Renders social icon links and expertise tag chips on the user profile page. |
| UI/src/features/pages/regular/profile/hooks/edit-profile.hook.ts | Sends newly added profile fields to the self-edit API payload. |
| UI/src/features/pages/regular/profile/edit-profile.tsx | Adds Social Links + Expertise Tags sections and client-side validation/counter UI. |
| UI/src/features/components/Expertisetagsinput.tsx | New autocomplete + freeSolo multi-tag input with tag limits/deduplication. |
| UI/src/features/components/CharacterCounter.tsx | New reusable character counter component for text inputs/editors. |
| UI/src/api/soroban-security-portal/models/user.ts | Extends user models with new fields and adds constants + URL validators. |
| UI/package-lock.json | Lockfile updates reflecting dependency graph metadata changes. |
Files not reviewed (1)
- UI/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
UI/src/features/pages/regular/profile/hooks/edit-profile.hook.ts
Outdated
Show resolved
Hide resolved
|
@pheobeayo please take a look at the comments |
0xGeorgii
left a comment
There was a problem hiding this comment.
@pheobeayo thank you for contributing, please address the following comments:
Critical Issues (Must Fix)
- Frontend-Backend Architecture Mismatch
This is the biggest problem. The PR adds bio, website, twitter, github, discord, and expertiseTags fields to SelfEditUserItem (which is sent via the user self-edit endpoint), but the backend already has a separate UserProfile system with its own API:
- Backend UserProfile API: PUT /api/v1/profiles/self — supports bio, website, expertiseTags, location
- Backend explicitly removed twitter_handle and github_handle columns in migration 20260127054059_RefactorUserProfileEntity.cs — these are now managed via ConnectedAccounts JSONB on LoginModel
The frontend should be calling the UserProfile API endpoints, not adding these fields to the user self-edit payload. As written, the backend will either ignore these fields or error, since SelfEditUserItem on the backend doesn't have website, twitter, github, discord, or expertiseTags properties.
Action: Refactor to use GET/PUT /api/v1/profiles/self for bio, website, and expertiseTags. For Twitter/GitHub/Discord, use the existing ConnectedAccounts system.
- XSS Vulnerability in isValidWebsiteUrl
File: UI/src/api/soroban-security-portal/models/user.ts
export function isValidWebsiteUrl(url: string): boolean {
if (!url) return true;
try { new URL(url); return true; } catch { return false; }
}
The URL constructor accepts javascript:, data:, vbscript: schemes. Since the validated URL is rendered into href on the profile page (), a user could set their website to
javascript:alert(document.cookie) — stored XSS.
Fix:
export function isValidWebsiteUrl(url: string): boolean {
if (!url) return true;
try {
const parsed = new URL(url.trim());
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
} catch { return false; }
}
- bio: '' Hardcoded — Data Loss on Every Save
File: UI/src/features/pages/regular/profile/hooks/edit-profile.hook.ts
const selfEditUserItem: SelfEditUserItem = {
// ...
bio: '' // Always empty — overwrites any existing bio
};
The bio field is added to the model but never populated from state. Every profile save sends bio: '', erasing existing data. Additionally, MAX_BIO_LENGTH is validated against aboutYou/personalInfo, suggesting confusion about whether bio and personalInfo are the same field.
- Discord Links Are Broken
File: UI/src/features/pages/regular/profile/profile.tsx
url: user?.discord ? https://discord.com/users/${user.discord} : undefined
The edit form collects a Discord username (placeholder: "your username"), but https://discord.com/users/ requires a numeric user ID. This produces broken links for every user. Render Discord as non-clickable text, or use the ConnectedAccounts data which has the actual OAuth account ID.
High Priority Issues
- File Naming Convention Violation
Expertisetagsinput.tsx uses inconsistent casing. Existing files in features/components/ use kebab-case (custom-toolbar.tsx, multimode-input.tsx). Should be expertise-tags-input.tsx, or move to src/components/ with PascalCase (ExpertiseTagsInput.tsx) since it's a reusable component.
- MUI v7 Deprecated InputProps
All four social link TextField components use the deprecated InputProps prop. MUI v7 (which this project uses) requires slotProps.input:
// Deprecated:
InputProps={{ startAdornment: ... }}
// MUI v7 correct:
slotProps={{ input: { startAdornment: ... } }}
- onBlur={validateSocials} Validates All Fields Simultaneously
Every social link field calls validateSocials on blur, which validates all three URL fields at once. Tabbing from Website to Twitter triggers validation on the still-empty GitHub field. Use per-field validation
instead.
- URL Regex Is Case-Sensitive
return /^https?://(www.)?(twitter.com|x.com)/[A-Za-z0-9_]{1,15}/?$/.test(url);
HTTPS://Twitter.com/username fails validation. Add the i flag to both isValidTwitterUrl and isValidGitHubUrl.
Medium Priority Issues
- Missing Trailing Newlines
All 6 modified/new files are missing trailing newlines (\ No newline at end of file).
- Duplicated Chip Styling
The expertise tag chip sx is duplicated verbatim between Expertisetagsinput.tsx and profile.tsx. Extract into a shared constant or small component.
- package-lock.json Contains Unrelated Churn
88 additions / 43 deletions are entirely peer: true flag toggling — no new dependencies. This suggests the lockfile was regenerated with a different npm version. Consider reverting: git checkout origin/main -- UI/package-lock.json.
- No Unit Tests
The URL validators are security-relevant code with no tests. ExpertiseTagsInput has non-trivial logic (deduplication, limits, Add "..." pattern matching) that should be tested.
Okay, I have updated the PR |
Done |
Extended User Profile with Bio, Social Links, and Expertise Tags
Demo video: https://www.loom.com/share/70a29c953d36405e80e8f3db0c61ced1
fixes and closes #70