Skip to content

Conversation

@vas3a
Copy link
Collaborator

@vas3a vas3a commented Jan 13, 2026

Bring back and re-enable the profile nudges for members.

@vas3a vas3a requested a review from kkartunov January 13, 2026 07:23
},
};
if (!DISABLE_NUDGES) {
const completednessData = await fetchUserProfileCompletedness(user, true);

Choose a reason for hiding this comment

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

[⚠️ correctness]
The fetchUserProfileCompletedness function is called with user and true as arguments. Ensure that the second argument being true is intentional and correctly handled within the function, as it might affect the logic or performance if not properly managed.

};
if (!DISABLE_NUDGES) {
const completednessData = await fetchUserProfileCompletedness(user, true);
if (!completednessData) {

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Consider adding error handling for the fetchUserProfileCompletedness call. If it fails, the function will return early without updating the context, which might lead to inconsistent application state.

$ctx.auth = {
...$ctx.auth,
profileCompletionData: {
completed: completednessData.data?.percentComplete === 100,

Choose a reason for hiding this comment

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

[⚠️ correctness]
The check completednessData.data?.percentComplete === 100 assumes that percentComplete is always a number. Ensure that percentComplete is validated or defaulted to a number to avoid potential issues with non-numeric values.

@@ -0,0 +1,12 @@
const modulePath = BUILD_IS_PROD ? './nudge.js' : '../nudge-app/Nudge.svelte';

Choose a reason for hiding this comment

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

[❗❗ correctness]
The use of BUILD_IS_PROD suggests a reliance on a global variable or build-time constant. Ensure that BUILD_IS_PROD is defined and correctly set in all environments where this code will run to avoid unexpected behavior.

return import(/* @vite-ignore */ modulePath).then(d => d.default)
}

export const loadNudgeApp = async (ctx: any, targetEl: Element): Promise<void> => {

Choose a reason for hiding this comment

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

[⚠️ maintainability]
The use of any for the ctx parameter can lead to runtime errors if the context object does not have the expected structure. Consider defining a more specific type for ctx to improve type safety.

const locationHostname = window?.location.hostname ?? ''
return DISABLE_NUDGES ||
(!!NUDGES_DISABLED_HOSTS.find(host => (
host.match(new RegExp(`^https?:\/\/${locationHostname}`, 'i'))

Choose a reason for hiding this comment

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

[⚠️ correctness]
Using RegExp to match hostnames can be error-prone and may lead to unexpected matches. Consider using a more robust method to compare hostnames, such as direct string comparison or URL parsing.

}


let resolve!: (value: ProfileCompletednessResponse) => void;

Choose a reason for hiding this comment

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

[⚠️ correctness]
The resolve function is declared with a non-null assertion, which can lead to runtime errors if not handled correctly. Consider initializing resolve within the Promise constructor to ensure it's always defined.

const requestUrl: string = `${TC_API_HOST}/members/${userHandle}/profileCompleteness${toastOverrideFlag}`;
const request = fetch(requestUrl, {headers: {...getRequestAuthHeaders()}});

const response = await (await request).json();

Choose a reason for hiding this comment

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

[❗❗ correctness]
The fetch call does not handle HTTP errors. Consider checking the response status and handling errors appropriately to avoid unexpected failures.

...response,
data: {
...response.data,
percentComplete: (response?.data?.percentComplete ?? 0) * 100,

Choose a reason for hiding this comment

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

[⚠️ correctness]
Multiplying percentComplete by 100 suggests it might be intended to be a percentage. Ensure that this transformation aligns with how percentComplete is used elsewhere in the application.

height: 0;
width: 100%;
@include mobile {
--top-offset: 2px!important;

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Avoid using !important unless absolutely necessary, as it can make the CSS harder to maintain and override in the future. Consider restructuring the CSS to achieve the desired effect without !important.


const ctx = getAppContext();

$: ({

Choose a reason for hiding this comment

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

[⚠️ maintainability]
The use of $: for destructuring $ctx.auth is unconventional and might lead to confusion. Consider using a more explicit method to assign these values to improve readability and maintainability.

hideToast();
}

$: toast = isReady ? getToast(profileCompletionData as ProfileCompletionData) : undefined;

Choose a reason for hiding this comment

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

[❗❗ correctness]
Casting profileCompletionData to ProfileCompletionData without checking its actual type could lead to runtime errors if the assumption is incorrect. Consider adding a type guard or validation to ensure profileCompletionData is of the expected type.

height: 100%;

svg {
transform: none!important;

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Avoid using !important as it can make the CSS harder to maintain and override. Consider refactoring the CSS to achieve the desired effect without !important.

let coverRef: HTMLDivElement | undefined = undefined;
const dispatch = createEventDispatcher();

function triggerLoaded(animation: any = false) {

Choose a reason for hiding this comment

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

[⚠️ maintainability]
The animation parameter in triggerLoaded is typed as any. Consider using a more specific type to improve type safety and maintainability.

dispatch('loaded', {animation: animation === true});
}

const loadAnimation = (path) => {

Choose a reason for hiding this comment

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

[⚠️ maintainability]
The path parameter in loadAnimation is not typed. Consider specifying a type for better type safety and maintainability.

}

const loadAnimation = (path) => {
var animData = {

Choose a reason for hiding this comment

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

[💡 style]
Consider using const instead of var for animData to prevent potential issues with variable hoisting and to follow modern JavaScript practices.

progressiveLoad: true
},
};
const bmAnim = window['bodymovin'].loadAnimation(animData);

Choose a reason for hiding this comment

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

[❗❗ correctness]
Accessing window['bodymovin'] directly can lead to runtime errors if bodymovin is not loaded. Consider adding a check to ensure bodymovin is available before calling loadAnimation.

}

onMount(async () => {
await import(/* @vite-ignore */getPublicPath('/assets/nudge/bodymovin.js'));

Choose a reason for hiding this comment

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

[⚠️ security]
The use of /* @vite-ignore */ suggests that the import path might be dynamic. Ensure that this dynamic import is safe and that the path is always valid to prevent runtime errors.

pointer-events: none;
// move up and fade in when shown
transform: translate(0, -30px);
transition: transform 0.3s ease-in-out, opacity 0.18s ease-in-out 0.1s, visibility 0.01ms 0.3s;

Choose a reason for hiding this comment

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

[⚠️ correctness]
The use of visibility 0.01ms in the transition is unconventional and might not work as intended across all browsers. Consider revising this to a more standard approach or removing it if not necessary.

pointer-events: all;
// move down and fade out when hidden
transform: translate(0, 0);
transition: transform 0.3s ease-in-out, opacity 0.18s ease-in-out, visibility 0.01ms;

Choose a reason for hiding this comment

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

[⚠️ correctness]
Similar to line 21, the visibility 0.01ms in the transition might not behave as expected. Consider using a more conventional timing or removing it.

padding: 5px 15px;
border-radius: 25px;

background: tc-color(black, 100);

Choose a reason for hiding this comment

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

[⚠️ correctness]
The tc-color(black, 100) function usage is unclear without context. Ensure that this function is defined and behaves as expected, especially in terms of color contrast for accessibility.

transition: 0.15s ease-in-out;

&:hover {
background: tc-color(black, tc);

Choose a reason for hiding this comment

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

[⚠️ correctness]
The tc-color(black, tc) function usage should be verified for correctness and accessibility, as the parameter tc is not defined in this context.


function handleCloseKeydown(e: KeyboardEvent) {
const key = (e as KeyboardEvent).key;
if (key === 'Enter' || key === ' ' || key === 'Spacebar') {

Choose a reason for hiding this comment

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

[💡 readability]
The check for the 'Spacebar' key is redundant as it is deprecated and ' ' (space) should suffice. Consider removing 'Spacebar' for clarity.

<div class={styles.message}>{toast.message}</div>

<a
href={toast.ctaLink(userhandle)}

Choose a reason for hiding this comment

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

[❗❗ security]
Ensure that toast.ctaLink(userhandle) returns a safe URL to prevent potential security vulnerabilities such as open redirects.

* @returns
*/
export const getToast = (completednessData: ProfileCompletionData) => {
if (dismissNudgesBasedOnHost() || !completednessData || completednessData.completed || isToastDismissed()) {

Choose a reason for hiding this comment

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

[❗❗ correctness]
The condition !completednessData should be checked first to avoid potential null or undefined errors when accessing properties like completednessData.completed. Consider reordering the conditions for safety.

}

const toastToShow = lastToastSeen || completednessData.showToast;
return toastsMeta[toastToShow];

Choose a reason for hiding this comment

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

[⚠️ correctness]
Accessing toastsMeta[toastToShow] without checking if toastToShow is a valid key could lead to undefined behavior if toastToShow is not present in toastsMeta. Consider adding a check to ensure toastToShow is a valid key before accessing toastsMeta.

}

if (navType === 'tool' || navType === 'marketing') {
loadNudgeApp(ctx, targetEl.querySelector('.tc-universal-nav-wrap') as Element);

Choose a reason for hiding this comment

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

[❗❗ correctness]
Ensure that targetEl.querySelector('.tc-universal-nav-wrap') returns a valid element before passing it to loadNudgeApp. If it returns null, this will cause a runtime error. Consider adding a check to handle this case.

@@ -0,0 +1 @@
export default import('../lib/nudge-app/Nudge.svelte').then(d => d.default);

Choose a reason for hiding this comment

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

[⚠️ performance]
Using dynamic import() can impact performance as it introduces a runtime overhead. Consider using static imports if the module is not conditionally loaded or if tree-shaking is a concern.

@@ -0,0 +1 @@
export declare const loadNudgeApp: (ctx: any, targetEl: Element) => Promise<void>;

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Using any for the ctx parameter can lead to potential runtime errors and makes the function harder to understand and maintain. Consider using a more specific type or an interface to define the expected structure of ctx.

* Fetches the user profile completedness
* @returns Promise<ProfileCompletednessResponse>
*/
export declare const fetchUserProfileCompletedness: (user: AuthUser, force?: boolean) => Promise<ProfileCompletednessResponse | undefined>;

Choose a reason for hiding this comment

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

[⚠️ correctness]
The return type Promise<ProfileCompletednessResponse | undefined> suggests that the function might return undefined. Consider clarifying under what conditions undefined is returned, as this can impact how the function is used and error-handling strategies.

* @param completednessData
* @returns
*/
export declare const getToast: (completednessData: ProfileCompletionData) => import("lib/config/profile-toasts.config").ToastType | undefined;

Choose a reason for hiding this comment

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

[⚠️ correctness]
The function getToast relies on ProfileCompletionData and returns a ToastType from profile-toasts.config. Ensure that the ToastType correctly handles all possible states of ProfileCompletionData, especially edge cases where data might be incomplete or malformed.

@@ -0,0 +1,2 @@
declare const _default: Promise<typeof import("svelte").SvelteComponent>;

Choose a reason for hiding this comment

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

[⚠️ design]
Exporting a Promise of a component can lead to unexpected behavior if the consumer of this module does not handle the promise correctly. Consider exporting the component directly or providing a factory function that returns the promise to ensure proper usage.

@vas3a vas3a merged commit fb87b96 into master Jan 13, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants