* Improve consistency on useOpenX hooks

* Review other hooks

* i18n and minor fix

* Address feedback
Этот коммит содержится в:
Daniel Espino García
2024-10-24 10:52:01 +02:00
коммит произвёл GitHub
родитель 48c42fc588
Коммит 8214ffbacd
16 изменённых файлов: 93 добавлений и 92 удалений

Просмотреть файл

@@ -48,5 +48,5 @@ export function useControlModal<T>(modalData: ModalData<T>): ControlModal {
close: () => { close: () => {
dispatch(closeModal(modalData.modalId)); dispatch(closeModal(modalData.modalId));
}, },
}), [modalData]); }), [modalData, dispatch]);
} }

Просмотреть файл

@@ -18,20 +18,22 @@ type CopyResponse = {
const DEFAULT_COPY_TIMEOUT = 4000; const DEFAULT_COPY_TIMEOUT = 4000;
export default function useCopyText(options: CopyOptions): CopyResponse { export default function useCopyText({
text,
successCopyTimeout: successCopyTimeoutReceived,
trackCallback,
}: CopyOptions): CopyResponse {
const [copiedRecently, setCopiedRecently] = useState(false); const [copiedRecently, setCopiedRecently] = useState(false);
const [copyError, setCopyError] = useState(false); const [copyError, setCopyError] = useState(false);
const timerRef = useRef<NodeJS.Timeout | null>(null); const timerRef = useRef<NodeJS.Timeout | null>(null);
let successCopyTimeout = DEFAULT_COPY_TIMEOUT; let successCopyTimeout = DEFAULT_COPY_TIMEOUT;
if (options.successCopyTimeout || options.successCopyTimeout === 0) { if (successCopyTimeoutReceived || successCopyTimeoutReceived === 0) {
successCopyTimeout = options.successCopyTimeout; successCopyTimeout = successCopyTimeoutReceived;
} }
const onClick = useCallback(() => { const onClick = useCallback(() => {
if (options.trackCallback) { trackCallback?.();
options.trackCallback();
}
if (timerRef.current) { if (timerRef.current) {
clearTimeout(timerRef.current); clearTimeout(timerRef.current);
@@ -39,7 +41,7 @@ export default function useCopyText(options: CopyOptions): CopyResponse {
} }
const clipboard = navigator.clipboard; const clipboard = navigator.clipboard;
if (clipboard) { if (clipboard) {
clipboard.writeText(options.text). clipboard.writeText(text).
then(() => { then(() => {
setCopiedRecently(true); setCopiedRecently(true);
setCopyError(false); setCopyError(false);
@@ -50,7 +52,7 @@ export default function useCopyText(options: CopyOptions): CopyResponse {
}); });
} else { } else {
const textField = document.createElement('textarea'); const textField = document.createElement('textarea');
textField.innerText = options.text; textField.innerText = text;
textField.style.position = 'fixed'; textField.style.position = 'fixed';
textField.style.opacity = '0'; textField.style.opacity = '0';
@@ -72,7 +74,7 @@ export default function useCopyText(options: CopyOptions): CopyResponse {
setCopiedRecently(false); setCopiedRecently(false);
setCopyError(false); setCopyError(false);
}, successCopyTimeout); }, successCopyTimeout);
}, [options.text, successCopyTimeout]); }, [successCopyTimeout, text, trackCallback]);
return { return {
copiedRecently, copiedRecently,

Просмотреть файл

@@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {useCallback} from 'react';
import {defineMessage} from 'react-intl'; import {defineMessage} from 'react-intl';
import {useSelector} from 'react-redux'; import {useSelector} from 'react-redux';
@@ -12,23 +13,23 @@ type UseExpandOverageUsersCheckArgs = {
banner: 'global banner' | 'invite modal'; banner: 'global banner' | 'invite modal';
} }
const cta = defineMessage({
id: 'licensingPage.overageUsersBanner.cta',
defaultMessage: 'Contact Sales',
});
export const useExpandOverageUsersCheck = ({ export const useExpandOverageUsersCheck = ({
isWarningState, isWarningState,
banner, banner,
}: UseExpandOverageUsersCheckArgs) => { }: UseExpandOverageUsersCheckArgs) => {
const expandableLink = useSelector(getExpandSeatsLink); const expandableLink = useSelector(getExpandSeatsLink);
const cta = defineMessage({ const trackEventFn = useCallback((cta: 'Contact Sales' | 'Self Serve') => {
id: 'licensingPage.overageUsersBanner.cta',
defaultMessage: 'Contact Sales',
});
const trackEventFn = (cta: 'Contact Sales' | 'Self Serve') => {
trackEvent('insights', isWarningState ? 'click_true_up_warning' : 'click_true_up_error', { trackEvent('insights', isWarningState ? 'click_true_up_warning' : 'click_true_up_error', {
cta, cta,
banner, banner,
}); });
}; }, [banner, isWarningState]);
return { return {
cta, cta,

Просмотреть файл

@@ -1,7 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {useState} from 'react'; import {useCallback, useState} from 'react';
import {defineMessages} from 'react-intl';
import type {NotifyAdminRequest} from '@mattermost/types/cloud'; import type {NotifyAdminRequest} from '@mattermost/types/cloud';
@@ -19,14 +20,6 @@ export const NotifyStatus = {
export type NotifyStatusValues = ValueOf<typeof NotifyStatus>; export type NotifyStatusValues = ValueOf<typeof NotifyStatus>;
export const DefaultBtnText = {
NotifyAdmin: 'Notify your admin',
Notifying: 'Notifying...',
Notified: 'Admin notified!',
AlreadyNotified: 'Already notified!',
Failed: 'Try again later!',
} as const;
type ValueOf<T> = T[keyof T]; type ValueOf<T> = T[keyof T];
type UseNotifyAdminArgs = { type UseNotifyAdminArgs = {
@@ -45,25 +38,40 @@ type NotifyAdminArgs = {
}; };
} }
const messages = defineMessages({
[NotifyStatus.Started]: {
id: 'notify_admin_to_upgrade_cta.notify-admin.notifying',
defaultMessage: 'Notifying...',
},
[NotifyStatus.Success]: {
id: 'notify_admin_to_upgrade_cta.notify-admin.notified',
defaultMessage: 'Admin notified!',
},
[NotifyStatus.AlreadyComplete]: {
id: 'notify_admin_to_upgrade_cta.notify-admin.already_notified',
defaultMessage: 'Already notified!',
},
[NotifyStatus.Failed]: {
id: 'notify_admin_to_upgrade_cta.notify-admin.failed',
defaultMessage: 'Try again later!',
},
[NotifyStatus.NotStarted]: {
id: 'notify_admin_to_upgrade_cta.notify-admin.notify',
defaultMessage: 'Notify your admin',
},
});
export const useGetNotifyAdmin = (args: UseNotifyAdminArgs) => { export const useGetNotifyAdmin = (args: UseNotifyAdminArgs) => {
const [notifyStatus, setStatus] = useState<ValueOf<typeof NotifyStatus>>(NotifyStatus.NotStarted); const [notifyStatus, setStatus] = useState<ValueOf<typeof NotifyStatus>>(NotifyStatus.NotStarted);
const btnText = (status: ValueOf<typeof NotifyStatus>): {id: string; defaultMessage: string} => { const btnText = useCallback((status: ValueOf<typeof NotifyStatus>): {id: string; defaultMessage: string} => {
switch (status) { if (args.ctaText && status === NotifyStatus.NotStarted) {
case NotifyStatus.Started: return args.ctaText;
return {id: 'notify_admin_to_upgrade_cta.notify-admin.notifying', defaultMessage: DefaultBtnText.Notifying};
case NotifyStatus.Success:
return {id: 'notify_admin_to_upgrade_cta.notify-admin.notified', defaultMessage: DefaultBtnText.Notified};
case NotifyStatus.AlreadyComplete:
return {id: 'notify_admin_to_upgrade_cta.notify-admin.already_notified', defaultMessage: DefaultBtnText.AlreadyNotified};
case NotifyStatus.Failed:
return {id: 'notify_admin_to_upgrade_cta.notify-admin.failed', defaultMessage: DefaultBtnText.Failed};
default:
return args.ctaText || {id: 'notify_admin_to_upgrade_cta.notify-admin.notify', defaultMessage: DefaultBtnText.NotifyAdmin};
} }
}; return messages[status];
}, [args.ctaText]);
const notifyAdmin = async ({requestData, trackingArgs}: NotifyAdminArgs) => { const notifyAdmin = useCallback(async ({requestData, trackingArgs}: NotifyAdminArgs) => {
try { try {
setStatus(NotifyStatus.Started); setStatus(NotifyStatus.Started);
await Client4.notifyAdmin(requestData); await Client4.notifyAdmin(requestData);
@@ -76,7 +84,7 @@ export const useGetNotifyAdmin = (args: UseNotifyAdminArgs) => {
setStatus(NotifyStatus.Failed); setStatus(NotifyStatus.Failed);
} }
} }
}; }, []);
return { return {
notifyStatus, notifyStatus,

Просмотреть файл

@@ -10,12 +10,12 @@ const useGetTotalUsersNoBots = (includeInactive = false): number => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [userCount, setUserCount] = useState<number>(0); const [userCount, setUserCount] = useState<number>(0);
const getTotalUsers = async () => {
const {data} = await dispatch(getFilteredUsersStats({include_bots: false, include_deleted: includeInactive}, false));
setUserCount(data?.total_users_count ?? 0);
};
useEffect(() => { useEffect(() => {
const getTotalUsers = async () => {
const {data} = await dispatch(getFilteredUsersStats({include_bots: false, include_deleted: includeInactive}, false));
setUserCount(data?.total_users_count ?? 0);
};
getTotalUsers(); getTotalUsers();
}, []); }, []);

Просмотреть файл

@@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {useCallback} from 'react';
import {useDispatch} from 'react-redux'; import {useDispatch} from 'react-redux';
import {trackEvent} from 'actions/telemetry_actions'; import {trackEvent} from 'actions/telemetry_actions';
@@ -17,7 +18,7 @@ type TelemetryProps = Pick<OpenDowngradeModalOptions, 'trackingLocation'>
export default function useOpenDowngradeModal() { export default function useOpenDowngradeModal() {
const dispatch = useDispatch(); const dispatch = useDispatch();
return (telemetryProps: TelemetryProps) => { return useCallback((telemetryProps: TelemetryProps) => {
trackEvent(TELEMETRY_CATEGORIES.CLOUD_ADMIN, 'click_open_downgrade_modal', { trackEvent(TELEMETRY_CATEGORIES.CLOUD_ADMIN, 'click_open_downgrade_modal', {
callerInfo: telemetryProps.trackingLocation, callerInfo: telemetryProps.trackingLocation,
}); });
@@ -25,5 +26,5 @@ export default function useOpenDowngradeModal() {
modalId: ModalIdentifiers.DOWNGRADE_MODAL, modalId: ModalIdentifiers.DOWNGRADE_MODAL,
dialogType: DowngradeModal, dialogType: DowngradeModal,
})); }));
}; }, [dispatch]);
} }

Просмотреть файл

@@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {useCallback} from 'react';
import {useDispatch} from 'react-redux'; import {useDispatch} from 'react-redux';
import {trackEvent} from 'actions/telemetry_actions'; import {trackEvent} from 'actions/telemetry_actions';
@@ -12,11 +13,11 @@ import {ModalIdentifiers} from 'utils/constants';
export default function useOpenInvitePeopleModal() { export default function useOpenInvitePeopleModal() {
const dispatch = useDispatch(); const dispatch = useDispatch();
return () => { return useCallback(() => {
trackEvent('invite_people', 'click_open_invite_people_modal'); trackEvent('invite_people', 'click_open_invite_people_modal');
dispatch(openModal({ dispatch(openModal({
modalId: ModalIdentifiers.INVITATION, modalId: ModalIdentifiers.INVITATION,
dialogType: InvitationModal, dialogType: InvitationModal,
})); }));
}; }, [dispatch]);
} }

Просмотреть файл

@@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {useCallback} from 'react';
import {useDispatch, useSelector} from 'react-redux'; import {useDispatch, useSelector} from 'react-redux';
import {isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud'; import {isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud';
@@ -19,8 +20,9 @@ export type TelemetryProps = {
export default function useOpenPricingModal() { export default function useOpenPricingModal() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const isCloud = useSelector(isCurrentLicenseCloud); const isCloud = useSelector(isCurrentLicenseCloud);
let category; const openPricingModal = useCallback((telemetryProps?: TelemetryProps) => {
return (telemetryProps?: TelemetryProps) => { let category;
if (isCloud) { if (isCloud) {
category = TELEMETRY_CATEGORIES.CLOUD_PRICING; category = TELEMETRY_CATEGORIES.CLOUD_PRICING;
} else { } else {
@@ -36,5 +38,7 @@ export default function useOpenPricingModal() {
callerCTA: telemetryProps?.trackingLocation, callerCTA: telemetryProps?.trackingLocation,
}, },
})); }));
}; }, [dispatch, isCloud]);
return openPricingModal;
} }

Просмотреть файл

@@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {useCallback} from 'react';
import {useSelector} from 'react-redux'; import {useSelector} from 'react-redux';
import {getCloudCustomer, isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud'; import {getCloudCustomer, isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud';
@@ -9,6 +10,8 @@ import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import {LicenseLinks} from 'utils/constants'; import {LicenseLinks} from 'utils/constants';
import {buildMMURL, goToMattermostContactSalesForm} from 'utils/contact_support_sales'; import {buildMMURL, goToMattermostContactSalesForm} from 'utils/contact_support_sales';
const utmSource = 'mattermost';
export default function useOpenSalesLink(): [() => void, string] { export default function useOpenSalesLink(): [() => void, string] {
const isCloud = useSelector(isCurrentLicenseCloud); const isCloud = useSelector(isCurrentLicenseCloud);
const customer = useSelector(getCloudCustomer); const customer = useSelector(getCloudCustomer);
@@ -17,7 +20,6 @@ export default function useOpenSalesLink(): [() => void, string] {
let firstName = ''; let firstName = '';
let lastName = ''; let lastName = '';
let companyName = ''; let companyName = '';
const utmSource = 'mattermost';
let utmMedium = 'in-product'; let utmMedium = 'in-product';
if (isCloud && customer) { if (isCloud && customer) {
@@ -31,8 +33,9 @@ export default function useOpenSalesLink(): [() => void, string] {
} }
const contactSalesLink = buildMMURL(LicenseLinks.CONTACT_SALES, firstName, lastName, companyName, customerEmail, utmSource, utmMedium); const contactSalesLink = buildMMURL(LicenseLinks.CONTACT_SALES, firstName, lastName, companyName, customerEmail, utmSource, utmMedium);
const goToSalesLinkFunc = () => { const goToSalesLinkFunc = useCallback(() => {
goToMattermostContactSalesForm(firstName, lastName, companyName, customerEmail, utmSource, utmMedium); goToMattermostContactSalesForm(firstName, lastName, companyName, customerEmail, utmSource, utmMedium);
}; }, [firstName, lastName, companyName, customerEmail, utmMedium]);
return [goToSalesLinkFunc, contactSalesLink]; return [goToSalesLinkFunc, contactSalesLink];
} }

Просмотреть файл

@@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {useCallback} from 'react';
import {useDispatch} from 'react-redux'; import {useDispatch} from 'react-redux';
import {openModal} from 'actions/views/modals'; import {openModal} from 'actions/views/modals';
@@ -13,7 +14,7 @@ import type {TelemetryProps} from './useOpenPricingModal';
export default function useOpenStartTrialFormModal() { export default function useOpenStartTrialFormModal() {
const dispatch = useDispatch(); const dispatch = useDispatch();
return (telemetryProps?: TelemetryProps, onClose?: () => void) => { return useCallback((telemetryProps?: TelemetryProps, onClose?: () => void) => {
dispatch(openModal({ dispatch(openModal({
modalId: ModalIdentifiers.START_TRIAL_FORM_MODAL, modalId: ModalIdentifiers.START_TRIAL_FORM_MODAL,
dialogType: StartTrialFormModal, dialogType: StartTrialFormModal,
@@ -22,5 +23,5 @@ export default function useOpenStartTrialFormModal() {
onClose, onClose,
}, },
})); }));
}; }, [dispatch]);
} }

Просмотреть файл

@@ -1,12 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {useCallback} from 'react';
import {useSelector} from 'react-redux'; import {useSelector} from 'react-redux';
import {getCloudCustomer} from 'mattermost-redux/selectors/entities/cloud'; import {getCloudCustomer} from 'mattermost-redux/selectors/entities/cloud';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import {getCloudSupportLink, getSelfHostedSupportLink, goToCloudSupportForm, goToSelfHostedSupportForm} from 'utils/contact_support_sales'; import {getCloudSupportLink, goToCloudSupportForm} from 'utils/contact_support_sales';
export function useOpenCloudZendeskSupportForm(subject: string, description: string): [() => void, string] { export function useOpenCloudZendeskSupportForm(subject: string, description: string): [() => void, string] {
const customer = useSelector(getCloudCustomer); const customer = useSelector(getCloudCustomer);
@@ -14,14 +14,9 @@ export function useOpenCloudZendeskSupportForm(subject: string, description: str
const url = getCloudSupportLink(customerEmail, subject, description, window.location.host); const url = getCloudSupportLink(customerEmail, subject, description, window.location.host);
return [() => goToCloudSupportForm(customerEmail, subject, description, window.location.host), url]; const openContactSupport = useCallback(
} () => goToCloudSupportForm(customerEmail, subject, description, window.location.host),
[customerEmail, subject, description],
export function useOpenSelfHostedZendeskSupportForm(subject: string): [() => void, string] { );
const currentUser = useSelector(getCurrentUser); return [openContactSupport, url];
const customerEmail = currentUser.email || '';
const url = getSelfHostedSupportLink(customerEmail, subject);
return [() => goToSelfHostedSupportForm(customerEmail, subject), url];
} }

Просмотреть файл

@@ -27,7 +27,7 @@ export default function usePreference(category: string, name: string): [string |
value, value,
}; };
return dispatch(savePreferences(userId, [preference])); return dispatch(savePreferences(userId, [preference]));
}, [category, name, userId]); }, [category, dispatch, name, userId]);
return useMemo(() => ([preferenceValue, setPreference]), [preferenceValue, setPreference]); return useMemo(() => ([preferenceValue, setPreference]), [preferenceValue, setPreference]);
} }

Просмотреть файл

@@ -18,7 +18,7 @@ export default function useSavePreferences(): (preferences: MinimalPreferenceTyp
const preferencesList = ((preferences as MinimalPreferenceType[]).length ? preferences : [preferences]) as MinimalPreferenceType[]; const preferencesList = ((preferences as MinimalPreferenceType[]).length ? preferences : [preferences]) as MinimalPreferenceType[];
const preferencesListWithUserId: PreferenceType[] = preferencesList.map((x) => ({...x, user_id: userId})); const preferencesListWithUserId: PreferenceType[] = preferencesList.map((x) => ({...x, user_id: userId}));
dispatch(savePreferences(userId, preferencesListWithUserId)); dispatch(savePreferences(userId, preferencesListWithUserId));
}, [userId]); }, [dispatch, userId]);
} }
type MinimalBoolPreferenceType = Omit<MinimalPreferenceType, 'value'> & {value?: boolean} type MinimalBoolPreferenceType = Omit<MinimalPreferenceType, 'value'> & {value?: boolean}

Просмотреть файл

@@ -24,8 +24,6 @@ function useTelemetryIdentitySync() {
Client4.setUserRoles(userRoles); Client4.setUserRoles(userRoles);
} }
}, [userId, userRoles]); }, [userId, userRoles]);
return null;
} }
export default useTelemetryIdentitySync; export default useTelemetryIdentitySync;

Просмотреть файл

@@ -4444,6 +4444,11 @@
"no_results.user_groups.title": "No groups yet", "no_results.user_groups.title": "No groups yet",
"notification.crt": "Reply in {title}", "notification.crt": "Reply in {title}",
"notification.dm": "Direct Message", "notification.dm": "Direct Message",
"notify_admin_to_upgrade_cta.notify-admin.already_notified": "Already notified!",
"notify_admin_to_upgrade_cta.notify-admin.failed": "Try again later!",
"notify_admin_to_upgrade_cta.notify-admin.notified": "Admin notified!",
"notify_admin_to_upgrade_cta.notify-admin.notify": "Notify your admin",
"notify_admin_to_upgrade_cta.notify-admin.notifying": "Notifying...",
"notify_all.confirm": "Confirm", "notify_all.confirm": "Confirm",
"notify_all.title.confirm": "Confirm Sending Notifications to Entire Channel", "notify_all.title.confirm": "Confirm Sending Notifications to Entire Channel",
"notify_all.title.confirm_groups": "Confirm sending notifications to groups", "notify_all.title.confirm_groups": "Confirm sending notifications to groups",

Просмотреть файл

@@ -40,24 +40,6 @@ export const buildZendeskSupportForm = (form: ZendeskSupportForm, formFieldIDs:
return formUrl; return formUrl;
}; };
export const goToSelfHostedSupportForm = (email: string, subject: string) => {
const form = ZendeskSupportForm.SELF_HOSTED_SUPPORT_FORM;
const url = buildZendeskSupportForm(form, [
{id: ZendeskFormFieldIDs.EMAIL, val: email},
{id: ZendeskFormFieldIDs.SUBJECT, val: subject},
]);
window.open(url, '_blank');
};
export const getSelfHostedSupportLink = (email: string, subject: string) => {
const form = ZendeskSupportForm.SELF_HOSTED_SUPPORT_FORM;
const url = buildZendeskSupportForm(form, [
{id: ZendeskFormFieldIDs.EMAIL, val: email},
{id: ZendeskFormFieldIDs.SUBJECT, val: subject},
]);
return url;
};
export const goToCloudSupportForm = (email: string, subject: string, description: string, workspaceURL: string) => { export const goToCloudSupportForm = (email: string, subject: string, description: string, workspaceURL: string) => {
const form = ZendeskSupportForm.CLOUD_SUPPORT_FORM; const form = ZendeskSupportForm.CLOUD_SUPPORT_FORM;
let url = buildZendeskSupportForm(form, [ let url = buildZendeskSupportForm(form, [