Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/components/application/detail-header.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
@text="Edit"
@variant="light"
@class="btn--xs"
@disabled={{this.isEditDisabled}}
@onClick={{this.editApplication}}
@test="edit-button"
/>
Expand Down
95 changes: 80 additions & 15 deletions app/components/application/detail-header.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { TOAST_OPTIONS } from '../../constants/toast-options';
import { NUDGE_APPLICATION_URL } from '../../constants/apis';
import apiRequest from '../../utils/api-request';

const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000;

function isWithinCooldown(timestamp, cooldownMs = TWENTY_FOUR_HOURS) {
if (!timestamp) {
return false;
}

const now = Date.now();
const time = new Date(timestamp).getTime();

return now - time < cooldownMs;
}

export default class DetailHeader extends Component {
@service router;
@service toast;

@tracked isLoading = false;
get application() {
return this.args.application;
}
Expand Down Expand Up @@ -41,20 +63,29 @@ export default class DetailHeader extends Component {
}

get nudgeCount() {
return this.application?.nudgeCount ?? 0;
return this.args.nudgeCount ?? this.application?.nudgeCount ?? 0;
}

get lastNudgeAt() {
return this.args.lastNudgeAt ?? this.application?.lastNudgeAt ?? null;
}

get lastEditAt() {
return this.application?.lastEditAt ?? null;
}

get isNudgeDisabled() {
if (this.status !== 'pending') {
if (this.isLoading || this.status !== 'pending') {
return true;
}
if (!this.application?.lastNudgedAt) {
return false;
return isWithinCooldown(this.lastNudgeAt);
}

get isEditDisabled() {
if (this.isLoading) {
return true;
}
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;
return isWithinCooldown(this.lastEditAt);
}

get socialLinks() {
Expand All @@ -80,20 +111,54 @@ export default class DetailHeader extends Component {
}

@action
nudgeApplication() {
//ToDo: Implement logic for callling nudge API here
console.log('nudge application');
async nudgeApplication() {
this.isLoading = true;

try {
const response = await apiRequest(
NUDGE_APPLICATION_URL(this.application.id),
'PATCH',
);

if (!response.ok) {
throw new Error(`Nudge failed: ${response.status}`);
}

const data = await response.json();

const updatedNudgeData = {
nudgeCount: data?.nudgeCount ?? this.nudgeCount + 1,
lastNudgeAt: data?.lastNudgeAt ?? new Date().toISOString(),
};

this.toast.success(
'Nudge successful, you will be able to nudge again after 24hrs',
'Success!',
TOAST_OPTIONS,
);

this.args.onNudge?.(updatedNudgeData);
} catch (error) {
console.error('Nudge failed:', error);
this.toast.error('Failed to nudge application', 'Error!', TOAST_OPTIONS);
} finally {
this.isLoading = false;
}
}

@action
editApplication() {
//ToDo: Implement logic for edit application here
console.log('edit application');
this.router.transitionTo('join', {
queryParams: {
edit: true,
dev: true,
step: 1,
},
});
}

@action
navigateToDashboard() {
//ToDo: Navigate to dashboard site for admin actions
console.log('navigate to dashboard');
this.router.transitionTo(`/intro?id=${this.userDetails?.id}`);
}
}
28 changes: 19 additions & 9 deletions app/components/join-steps/status-card.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,25 @@
<div class="joining__copy">
<h3 class="details" data-test-link-text>Here is your personalized link</h3>
<p id="url" class="copy__link">{{this.introLink}}</p>
<CopyButton
data-test-copy-btn
@target="#url"
@onSuccess={{this.onSuccess}}
@onError={{this.onError}}
class="btn btn-dark"
>
Copy
</CopyButton>

<div class="status-card__buttons">
<CopyButton
data-test-copy-btn
@target="#url"
@onSuccess={{this.onSuccess}}
@onError={{this.onError}}
class="btn btn-dark"
>
Copy
</CopyButton>
<Reusables::Button
@text="Track Application"
@variant="dark"
@onClick={{this.trackApplication}}
@test="track-application-btn"
@type="button"
/>
</div>
</div>
{{/if}}

Expand Down
14 changes: 14 additions & 0 deletions app/components/join-steps/status-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export default class StatusCardComponent extends Component {
return USER_JOINED_LINK(this.login.userData.id);
}

get applicationId() {
return this.onboarding.applicationData?.id;
}

@action
async fetchStatus() {
await this.onboarding.getApplicationDetails();
Expand Down Expand Up @@ -96,4 +100,14 @@ export default class StatusCardComponent extends Component {
onError() {
this.toast.error('Error in copying to clipboard', 'Error!', TOAST_OPTIONS);
}

@action
trackApplication() {
if (this.applicationId) {
// ToDo: remove dev=true once feature flag is removed from application detail apge
this.router.transitionTo('applications.detail', this.applicationId, {
queryParams: { dev: true },
});
}
}
}
74 changes: 60 additions & 14 deletions app/components/new-join-steps/base-step.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,85 @@
import { action } from '@ember/object';
import Component from '@glimmer/component';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { debounceTask } from 'ember-lifeline';
import { debounceTask, runTask } from 'ember-lifeline';
import { JOIN_DEBOUNCE_TIME } from '../../constants/join';
import { USER_ROLE_MAP } from '../../constants/new-join-form';
import { validateWordCount } from '../../utils/validator';
import { getLocalStorageItem, setLocalStorageItem } from '../../utils/storage';

export default class BaseStepComponent extends Component {
@service onboarding;

stepValidation = {};

@tracked data = {};
@tracked errorMessage = {};
@tracked wordCount = {};

get storageKey() {
return '';
}

postLoadInitialize() {}

STEP_FORM_DATA_MAPPING = {
newStepOneData: (app) => ({
firstName: app.biodata?.firstName || '',
lastName: app.biodata?.lastName || '',
city: app.location?.city || '',
state: app.location?.state || '',
country: app.location?.country || '',
role:
Object.keys(USER_ROLE_MAP).find(
(key) => USER_ROLE_MAP[key] === app.role,
) || '',
imageUrl: app.imageUrl || '',
}),
newStepTwoData: (app) => ({
institution: app.professional?.institution || '',
skills: app.professional?.skills || '',
introduction: app.intro?.introduction || '',
}),
newStepThreeData: (app) => ({
forFun: app.intro?.forFun || '',
funFact: app.intro?.funFact || '',
}),
newStepFourData: (app) => ({
phoneNumber: app.socialLink?.phoneNumber || '',
twitter: app.socialLink?.twitter || '',
linkedin: app.socialLink?.linkedin || '',
instagram: app.socialLink?.instagram || '',
github: app.socialLink?.github || '',
peerlist: app.socialLink?.peerlist || '',
behance: app.socialLink?.behance || '',
dribble: app.socialLink?.dribble || '',
}),
newStepFiveData: (app) => ({
whyRds: app.intro?.whyRds || '',
foundFrom: app.foundFrom || '',
numberOfHours: app.intro?.numberOfHours || '',
}),
};

constructor(...args) {
super(...args);
this.initializeFormState();
}

initializeFormState() {
let saved = {};
try {
const stored = getLocalStorageItem(this.storageKey, '{}');
saved = stored ? JSON.parse(stored) : {};
} catch (e) {
console.warn('Failed to parse stored form data:', e);
saved = {};
const storedData = getLocalStorageItem(this.storageKey, '{}');
let initialFormData = storedData ? JSON.parse(storedData) : {};

if (
Object.keys(initialFormData).length === 0 &&
this.onboarding.applicationData
) {
const stepDataMapper = this.STEP_FORM_DATA_MAPPING[this.storageKey];

if (stepDataMapper) {
initialFormData = stepDataMapper(this.onboarding.applicationData);
setLocalStorageItem(this.storageKey, JSON.stringify(initialFormData));
}
}
this.data = saved;

this.data = initialFormData;

this.errorMessage = Object.fromEntries(
Object.keys(this.stepValidation).map((k) => [k, '']),
Expand All @@ -46,7 +92,7 @@ export default class BaseStepComponent extends Component {
}),
);

this.postLoadInitialize();
runTask(this, 'postLoadInitialize');

const valid = this.isDataValid();
this.args.setIsPreValid(valid);
Expand Down
4 changes: 3 additions & 1 deletion app/components/new-join-steps/new-step-five.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
import { heardFrom } from '../../constants/social-data';

export default class NewStepFiveComponent extends BaseStepComponent {
storageKey = STEP_DATA_STORAGE_KEY.stepFive;
get storageKey() {
return STEP_DATA_STORAGE_KEY.stepFive;
}
heardFrom = heardFrom;

stepValidation = {
Expand Down
4 changes: 3 additions & 1 deletion app/components/new-join-steps/new-step-four.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
import { phoneNumberRegex } from '../../constants/regex';

export default class NewStepFourComponent extends BaseStepComponent {
storageKey = STEP_DATA_STORAGE_KEY.stepFour;
get storageKey() {
return STEP_DATA_STORAGE_KEY.stepFour;
}

stepValidation = {
phoneNumber: NEW_STEP_LIMITS.stepFour.phoneNumber,
Expand Down
6 changes: 3 additions & 3 deletions app/components/new-join-steps/new-step-one.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
<div class="two-column-layout__left">
<h3 class="section-heading">Profile Picture</h3>
{{#if this.isImageUploading}}
<div class="image-preview-container">
<Spinner />
<div class="image-preview-loading">
<p>Processing image...</p>
</div>
{{else}}
Expand All @@ -13,6 +12,7 @@
src={{this.imagePreview}}
alt="Profile preview"
class="image-preview"
data-test-image-preview
/>
<Reusables::Button
@type="button"
Expand Down Expand Up @@ -68,7 +68,7 @@
@type="text"
@disabled={{true}}
@required={{true}}
@value={{this.data.fullName}}
@value={{this.fullName}}
@onInput={{this.inputHandler}}
/>

Expand Down
Loading