-
Notifications
You must be signed in to change notification settings - Fork 153
feat: add application detail page #1130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
6c3f035
feat: add application detail page
MayankBansal12 cb838ff
Merge branch 'develop' into feat/application-detail
MayankBansal12 2aa61dd
refactor: remove unused getters, simplify info card section
MayankBansal12 9bd155a
fix: incorrect usage of lastNudge and invalid linkedin url
MayankBansal12 3bea898
test: add unit and integration tests for application detail page (#1137)
MayankBansal12 484db8e
Merge branch 'develop' into feat/application-detail
MayankBansal12 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| <div class="detail-header" data-test-detail-header> | ||
| <div class="detail-header-left" data-test-header-profile> | ||
| <div class="header-profile"> | ||
| <img | ||
| src={{this.imageUrl}} | ||
| alt="Profile" | ||
| class="profile-image" | ||
| data-test-profile-image | ||
| /> | ||
| <div class="profile-info"> | ||
| <div class="profile-name-row"> | ||
| <h2 class="user-name" data-test-user-name> | ||
| {{this.fullName}} | ||
| </h2> | ||
| <Application::StatusBadge @status={{this.status}} /> | ||
| </div> | ||
| <p class="profile-role">{{this.role}}</p> | ||
| <div class="profile-meta"> | ||
| <div class="meta-item"> | ||
| <IconifyIcon @icon="mdi:map-marker" /> | ||
| {{this.location}} | ||
| </div> | ||
| <div class="meta-item"> | ||
| <IconifyIcon @icon="mdi:lightbulb-on" /> | ||
| {{this.skills}} | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="social-links-container" data-test-social-links-container> | ||
| {{#each this.socialLinks as |link|}} | ||
| <Application::SocialLinkPill | ||
| @platform={{link.platform}} | ||
| @userName={{link.userName}} | ||
| data-test-social-link | ||
| /> | ||
| {{/each}} | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="detail-header-right"> | ||
| <div class="header-score-nudge" data-test-header-score-nudge> | ||
| <div class="score-display" data-test-score-display> | ||
| <span class="score-value" data-test-score-value>{{this.score}}</span> | ||
| <span class="score-label">Score</span> | ||
| </div> | ||
| <div class="score-display" data-test-nudge-details> | ||
| <span class="score-value">{{this.nudgeCount}}</span> | ||
| <span class="score-label">Nudges</span> | ||
| </div> | ||
| </div> | ||
| <div class="header-actions" data-test-header-actions> | ||
| {{#if @isAdmin}} | ||
| <Reusables::Button | ||
| @text="Dashboard" | ||
| @variant="dark" | ||
| @class="btn--xs" | ||
| @onClick={{this.navigateToDashboard}} | ||
| @test="navigate-button" | ||
| /> | ||
| {{else}} | ||
| <Reusables::Button | ||
| @text="Nudge" | ||
| @variant="dark" | ||
| @class="btn--xs" | ||
| @disabled={{this.isNudgeDisabled}} | ||
| @onClick={{this.nudgeApplication}} | ||
| @test="nudge-button" | ||
| /> | ||
| <Reusables::Button | ||
| @text="Edit" | ||
| @variant="light" | ||
| @class="btn--xs" | ||
| @onClick={{this.editApplication}} | ||
| @test="edit-button" | ||
| /> | ||
| {{/if}} | ||
| </div> | ||
| </div> | ||
| </div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| import Component from '@glimmer/component'; | ||
| import { action } from '@ember/object'; | ||
|
|
||
| export default class DetailHeader extends Component { | ||
| get application() { | ||
| return this.args.application; | ||
| } | ||
|
|
||
| get userDetails() { | ||
| return this.args.userDetails; | ||
| } | ||
|
|
||
| get fullName() { | ||
| const { firstName, lastName } = this.application?.biodata || {}; | ||
| return firstName || lastName ? `${firstName} ${lastName}` : null; | ||
| } | ||
|
|
||
| get imageUrl() { | ||
| return this.application?.imageUrl ?? ''; | ||
| } | ||
|
|
||
| get role() { | ||
| return this.application?.role ?? 'N/A'; | ||
| } | ||
|
|
||
| get status() { | ||
| return this.application?.status ?? 'pending'; | ||
| } | ||
|
|
||
| get skills() { | ||
| return this.application?.professional?.skills ?? 'N/A'; | ||
| } | ||
|
|
||
| get location() { | ||
| const { city, state, country } = this.application?.location || {}; | ||
| return [city, state, country].filter(Boolean).join(', ') || 'N/A'; | ||
| } | ||
|
|
||
| get score() { | ||
| return this.application?.score ?? 'N/A'; | ||
| } | ||
|
|
||
| get nudgeCount() { | ||
| return this.application?.nudgeCount ?? 0; | ||
| } | ||
|
|
||
| get isNudgeDisabled() { | ||
| if (this.status !== 'pending') { | ||
| return true; | ||
| } | ||
| if (!this.application?.lastNudgedAt) { | ||
| return false; | ||
| } | ||
| const now = Date.now(); | ||
| const lastNudgeTime = new Date(this.application.lastNudgedAt).getTime(); | ||
| const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000; | ||
| return now - lastNudgeTime < TWENTY_FOUR_HOURS; | ||
| } | ||
|
|
||
| get socialLinks() { | ||
| const links = []; | ||
| const social = this.application?.socialLink || {}; | ||
|
|
||
| if (social.github) | ||
| links.push({ platform: 'GitHub', userName: social.github }); | ||
| if (social.linkedin) | ||
| links.push({ platform: 'LinkedIn', userName: social.linkedin }); | ||
| if (social.twitter) | ||
| links.push({ platform: 'Twitter', userName: social.twitter }); | ||
| if (social.instagram) | ||
| links.push({ platform: 'Instagram', userName: social.instagram }); | ||
| if (social.peerlist) | ||
| links.push({ platform: 'Peerlist', userName: social.peerlist }); | ||
| if (social.dribbble) | ||
| links.push({ platform: 'Dribbble', userName: social.dribbble }); | ||
| if (social.behance) | ||
| links.push({ platform: 'Behance', userName: social.behance }); | ||
|
|
||
| return links; | ||
| } | ||
|
|
||
| @action | ||
| nudgeApplication() { | ||
| //ToDo: Implement logic for callling nudge API here | ||
| console.log('nudge application'); | ||
| } | ||
|
|
||
| @action | ||
| editApplication() { | ||
| //ToDo: Implement logic for edit application here | ||
| console.log('edit application'); | ||
| } | ||
|
|
||
| @action | ||
| navigateToDashboard() { | ||
| //ToDo: Navigate to dashboard site for admin actions | ||
| console.log('navigate to dashboard'); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| <div class="feedback-card" data-test-feedback-card> | ||
| <div class="feedback-header" data-test-feedback-header> | ||
| <Application::StatusBadge @status={{@status}} data-test-status-badge /> | ||
| <span | ||
| class="feedback-date" | ||
| data-test-feedback-date | ||
| >{{this.formattedDate}}</span> | ||
| </div> | ||
| <div class="feedback-content" data-test-feedback-content> | ||
| <p class="feedback-text" data-test-feedback-text>{{@feedbackText}}</p> | ||
| <p class="feedback-reviewer" data-test-feedback-reviewer>by | ||
| {{@reviewerName}}</p> | ||
| </div> | ||
| </div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import Component from '@glimmer/component'; | ||
|
|
||
| export default class FeedbackCard extends Component { | ||
| get formattedDate() { | ||
| if (!this.args.createdAt) { | ||
| return 'N/A'; | ||
| } | ||
| const date = new Date(this.args.createdAt); | ||
| return isNaN(date.getTime()) ? 'N/A' : date.toLocaleDateString(); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| <div class="info-card" data-test-info-card> | ||
| <h3 class="info-card-title" data-test-info-card-title>{{@title}}</h3> | ||
| <div class="info-card-content" data-test-info-card-content> | ||
| {{#each @sections as |section|}} | ||
| <div class="info-section" data-test-info-section> | ||
| <label class="info-label">{{section.label}}</label> | ||
| <p class="info-value">{{section.value}}</p> | ||
| </div> | ||
| {{/each}} | ||
| </div> | ||
| </div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| <a | ||
| href={{this.redirectUrl}} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| class="social-link-pill" | ||
| data-test-social-link | ||
| data-test-platform={{@platform}} | ||
| > | ||
| <IconifyIcon @icon={{this.icon}} /> | ||
| <span>{{@platform}}</span> | ||
| </a> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import Component from '@glimmer/component'; | ||
| import { mapSocialIcons, mapSocialUrls } from '../../constants/applications'; | ||
|
|
||
| export default class SocialLinkPill extends Component { | ||
| get platform() { | ||
| return this.args.platform?.toLowerCase(); | ||
| } | ||
|
|
||
| get icon() { | ||
| return mapSocialIcons[this.platform] || 'mdi:link'; | ||
| } | ||
|
|
||
| get redirectUrl() { | ||
| return `${mapSocialUrls[this.platform]}/${this.args.userName}`; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| <span class="status-badge status-badge--{{@status}}" data-test-status-badge> | ||
| {{this.applicationStatus}} | ||
| </span> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import Component from '@glimmer/component'; | ||
| import { mapApplicationStatus } from '../../constants/applications'; | ||
|
|
||
| export default class StatusBadge extends Component { | ||
| get applicationStatus() { | ||
| const status = this.args.status?.toUpperCase(); | ||
| return ( | ||
| mapApplicationStatus[status] || mapApplicationStatus.PENDING | ||
| )?.toUpperCase(); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| {{#unless this.isLive}} | ||
| {{#if this.isScrollToTopVisible}} | ||
| <button class="btn__scroll" type="button" {{on "click" this.scrollToTop}}> | ||
| <img src="assets/icons/arrowup-icon.svg" alt="arrow up" /> | ||
| <img src="/assets/icons/arrowup-icon.svg" alt="arrow up" /> | ||
| </button> | ||
| {{/if}} | ||
| {{/unless}} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| export const mapApplicationStatus = { | ||
| ACCEPTED: 'accepted', | ||
| REJECTED: 'rejected', | ||
| CHANGES_REQUESTED: 'Changes Requested', | ||
| PENDING: 'pending', | ||
| }; | ||
|
|
||
| export const mapSocialIcons = { | ||
| github: 'mdi:github', | ||
| linkedin: 'mdi:linkedin', | ||
| twitter: 'mdi:twitter', | ||
| instagram: 'mdi:instagram', | ||
| peerlist: 'mdi:account-circle', | ||
| }; | ||
|
|
||
| export const mapSocialUrls = { | ||
| github: 'https://github.com', | ||
| linkedin: 'https://linkedin.com/in', | ||
| twitter: 'https://twitter.com', | ||
| instagram: 'https://instagram.com', | ||
| peerlist: 'https://peerlist.io', | ||
| dribbble: 'https://dribbble.com', | ||
| behance: 'https://behance.net', | ||
| }; | ||
|
|
||
| export function adminMessage(status) { | ||
| switch (status) { | ||
| case 'pending': | ||
| return 'Admins are reviewing your applications, please hold up and keep on nudging.'; | ||
| case 'accepted': | ||
| return 'Your application is approved, go back to join page to get join discord invite.'; | ||
| case 'rejected': | ||
| return 'Your application has been rejected. Look at the feedback for more information.'; | ||
| case 'changes_requested': | ||
| return 'Admin has requested changes on your application, please edit and submit again for review.'; | ||
| default: | ||
| return 'Unknown status'; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import Controller from '@ember/controller'; | ||
| import { adminMessage } from '../../constants/applications'; | ||
|
|
||
| export default class ApplicationsDetailController extends Controller { | ||
| get application() { | ||
| return this.model?.application; | ||
| } | ||
|
|
||
| get currentUser() { | ||
| return this.model?.currentUser; | ||
| } | ||
|
|
||
| get isAdmin() { | ||
| return this.currentUser?.roles?.super_user === true; | ||
| } | ||
|
|
||
| get isApplicant() { | ||
| return this.currentUser?.id === this.application?.userId; | ||
| } | ||
|
|
||
| get canAccessApplication() { | ||
| return this.isAdmin || this.isApplicant; | ||
| } | ||
|
|
||
| get aboutYouSections() { | ||
| return [ | ||
| { | ||
| label: 'Introduction', | ||
| value: this.application?.intro?.introduction || 'N/A', | ||
| }, | ||
| { label: 'Fun Fact', value: this.application?.intro?.funFact || 'N/A' }, | ||
| { label: 'For Fun', value: this.application?.intro?.forFun || 'N/A' }, | ||
| { label: 'Why Join Us', value: this.application?.intro?.whyRds || 'N/A' }, | ||
| ]; | ||
| } | ||
|
|
||
| get hasFeedback() { | ||
| return this.application?.feedback?.length > 0; | ||
| } | ||
|
|
||
| get showAdminMessage() { | ||
| return adminMessage(this.application?.status); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is required, since the assets weren't loading correctly for nested routes