Skip to content

Commit

Permalink
Merge pull request #43367 from JKobrynski/implementAllToggleActions
Browse files Browse the repository at this point in the history
  • Loading branch information
blimpich authored Jun 18, 2024
2 parents d3d4c32 + 9b805ba commit 86a2e3d
Show file tree
Hide file tree
Showing 14 changed files with 210 additions and 56 deletions.
3 changes: 2 additions & 1 deletion src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4882,9 +4882,10 @@ type Country = keyof typeof CONST.ALL_COUNTRIES;
type IOUType = ValueOf<typeof CONST.IOU.TYPE>;
type IOUAction = ValueOf<typeof CONST.IOU.ACTION>;
type IOURequestType = ValueOf<typeof CONST.IOU.REQUEST_TYPE>;
type FeedbackSurveyOptionID = ValueOf<Pick<ValueOf<typeof CONST.FEEDBACK_SURVEY_OPTIONS>, 'ID'>>;

type SubscriptionType = ValueOf<typeof CONST.SUBSCRIPTION.TYPE>;

export type {Country, IOUAction, IOUType, RateAndUnit, OnboardingPurposeType, IOURequestType, SubscriptionType};
export type {Country, IOUAction, IOUType, RateAndUnit, OnboardingPurposeType, IOURequestType, SubscriptionType, FeedbackSurveyOptionID};

export default CONST;
22 changes: 19 additions & 3 deletions src/components/FeedbackSurvey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
import type {FeedbackSurveyOptionID} from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import FixedFooter from './FixedFooter';
import FormAlertWithSubmitButton from './FormAlertWithSubmitButton';
import SingleOptionSelector from './SingleOptionSelector';
import Text from './Text';
import TextInput from './TextInput';

type FeedbackSurveyProps = {
/** Title of the survey */
Expand All @@ -19,14 +21,14 @@ type FeedbackSurveyProps = {
description: string;

/** Callback to be called when the survey is submitted */
onSubmit: (reason: Option) => void;
onSubmit: (reason: FeedbackSurveyOptionID, note?: string) => void;

/** Styles for the option row element */
optionRowStyles?: StyleProp<ViewStyle>;
};

type Option = {
key: string;
key: FeedbackSurveyOptionID;
label: TranslationPaths;
};

Expand All @@ -44,6 +46,7 @@ function FeedbackSurvey({title, description, onSubmit, optionRowStyles}: Feedbac

const selectCircleStyles: StyleProp<ViewStyle> = {borderColor: theme.border};
const [reason, setReason] = useState<Option>();
const [note, setNote] = useState('');
const [shouldShowReasonError, setShouldShowReasonError] = useState(false);

const handleOptionSelect = (option: Option) => {
Expand All @@ -57,7 +60,7 @@ function FeedbackSurvey({title, description, onSubmit, optionRowStyles}: Feedbac
return;
}

onSubmit(reason);
onSubmit(reason.key, note.trim());
};

return (
Expand All @@ -72,13 +75,26 @@ function FeedbackSurvey({title, description, onSubmit, optionRowStyles}: Feedbac
selectedOptionKey={reason?.key}
onSelectOption={handleOptionSelect}
/>
{!!reason && (
<>
<Text style={[styles.textNormalThemeText, styles.mb3]}>{translate('feedbackSurvey.additionalInfoTitle')}</Text>
<TextInput
label={translate('feedbackSurvey.additionalInfoInputLabel')}
accessibilityLabel={translate('feedbackSurvey.additionalInfoInputLabel')}
role={CONST.ROLE.PRESENTATION}
onChangeText={setNote}
value={note}
/>
</>
)}
</View>
<FixedFooter>
<FormAlertWithSubmitButton
isAlertVisible={shouldShowReasonError}
onSubmit={handleSubmit}
message="common.error.pleaseCompleteForm"
buttonText={translate('common.submit')}
enabledWhenOffline
/>
</FixedFooter>
</View>
Expand Down
14 changes: 7 additions & 7 deletions src/components/SingleOptionSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@ import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
import SelectCircle from './SelectCircle';
import Text from './Text';

type Item = {
key: string;
type Item<TKey extends string> = {
key: TKey;
label: TranslationPaths;
};

type SingleOptionSelectorProps = {
type SingleOptionSelectorProps<TKey extends string> = {
/** Array of options for the selector, key is a unique identifier, label is a localize key that will be translated and displayed */
options?: Item[];
options?: Array<Item<TKey>>;

/** Key of the option that is currently selected */
selectedOptionKey?: string;
selectedOptionKey?: TKey;

/** Function to be called when an option is selected */
onSelectOption?: (item: Item) => void;
onSelectOption?: (item: Item<TKey>) => void;

/** Styles for the option row element */
optionRowStyles?: StyleProp<ViewStyle>;
Expand All @@ -31,7 +31,7 @@ type SingleOptionSelectorProps = {
selectCircleStyles?: StyleProp<ViewStyle>;
};

function SingleOptionSelector({options = [], selectedOptionKey, onSelectOption = () => {}, optionRowStyles, selectCircleStyles}: SingleOptionSelectorProps) {
function SingleOptionSelector<TKey extends string>({options = [], selectedOptionKey, onSelectOption = () => {}, optionRowStyles, selectCircleStyles}: SingleOptionSelectorProps<TKey>) {
const styles = useThemeStyles();
const {translate} = useLocalize();
return (
Expand Down
6 changes: 4 additions & 2 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3293,14 +3293,16 @@ export default {
'Automatically increase your annual seats to accommodate for active members that exceed your subscription size. Note: This will extend your annual subscription end date.',
disableAutoRenew: 'Disable auto-renew',
helpUsImprove: 'Help us improve Expensify',
whatsMainReason: 'Whats the main reason youre disabling auto-renew on your subscription?',
renewsOn: ({date}) => `Renews on ${date}`,
whatsMainReason: "What's the main reason you're disabling auto-renew?",
renewsOn: ({date}) => `Renews on ${date}.`,
},
},
feedbackSurvey: {
tooLimited: 'Functionality needs improvement',
tooExpensive: 'Too expensive',
inadequateSupport: 'Inadequate customer support',
businessClosing: 'Company closing, downsizing, or acquired',
additionalInfoTitle: 'What software are you moving to and why?',
additionalInfoInputLabel: 'Your response',
},
} satisfies TranslationBase;
6 changes: 4 additions & 2 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3797,14 +3797,16 @@ export default {
'Aumenta automáticamente tus plazas anuales para dar lugar a los miembros activos que superen el tamaño de tu suscripción. Nota: Esto ampliará la fecha de finalización de tu suscripción anual.',
disableAutoRenew: 'Desactivar auto-renovación',
helpUsImprove: 'Ayúdanos a mejorar Expensify',
whatsMainReason: '¿Cuál es la razón principal por la que deseas desactivar la auto-renovación de tu suscripción?',
renewsOn: ({date}) => `Se renovará el ${date}`,
whatsMainReason: '¿Cuál es la razón principal por la que deseas desactivar la auto-renovación?',
renewsOn: ({date}) => `Se renovará el ${date}.`,
},
},
feedbackSurvey: {
tooLimited: 'Hay que mejorar la funcionalidad',
tooExpensive: 'Demasiado caro',
inadequateSupport: 'Atención al cliente inadecuada',
businessClosing: 'Cierre, reducción, o adquisición de la empresa',
additionalInfoTitle: '¿A qué software está migrando y por qué?',
additionalInfoInputLabel: 'Tu respuesta',
},
} satisfies EnglishTranslation;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type UpdateSubscriptionAddNewUsersAutomaticallyParams = {
addNewUsersAutomatically: boolean;
};

export default UpdateSubscriptionAddNewUsersAutomaticallyParams;
9 changes: 9 additions & 0 deletions src/libs/API/parameters/UpdateSubscriptionAutoRenewParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type {FeedbackSurveyOptionID} from '@src/CONST';

type UpdateSubscriptionAutoRenewParams = {
autoRenew: boolean;
disableAutoRenewReason?: FeedbackSurveyOptionID;
disableAutoRenewAdditionalNote?: string;
};

export default UpdateSubscriptionAutoRenewParams;
2 changes: 2 additions & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,5 +227,7 @@ export type {default as PayInvoiceParams} from './PayInvoiceParams';
export type {default as MarkAsCashParams} from './MarkAsCashParams';
export type {default as UpdateSubscriptionTypeParams} from './UpdateSubscriptionTypeParams';
export type {default as SignUpUserParams} from './SignUpUserParams';
export type {default as UpdateSubscriptionAutoRenewParams} from './UpdateSubscriptionAutoRenewParams';
export type {default as UpdateSubscriptionAddNewUsersAutomaticallyParams} from './UpdateSubscriptionAddNewUsersAutomaticallyParams';
export type {default as GenerateSpotnanaTokenParams} from './GenerateSpotnanaTokenParams';
export type {default as UpdateSubscriptionSizeParams} from './UpdateSubscriptionSizeParams';
5 changes: 5 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ const WRITE_COMMANDS = {
MARK_AS_CASH: 'MarkAsCash',
UPDATE_SUBSCRIPTION_TYPE: 'UpdateSubscriptionType',
SIGN_UP_USER: 'SignUpUser',
UPDATE_SUBSCRIPTION_AUTO_RENEW: 'UpdateSubscriptionAutoRenew',
UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY: 'UpdateSubscriptionAddNewUsersAutomatically',
UPDATE_SUBSCRIPTION_SIZE: 'UpdateSubscriptionSize',
} as const;

Expand Down Expand Up @@ -449,6 +451,9 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.MARK_AS_CASH]: Parameters.MarkAsCashParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_TYPE]: Parameters.UpdateSubscriptionTypeParams;
[WRITE_COMMANDS.SIGN_UP_USER]: Parameters.SignUpUserParams;

[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_AUTO_RENEW]: Parameters.UpdateSubscriptionAutoRenewParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY]: Parameters.UpdateSubscriptionAddNewUsersAutomaticallyParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_SIZE]: Parameters.UpdateSubscriptionSizeParams;
};

Expand Down
124 changes: 118 additions & 6 deletions src/libs/actions/Subscription.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type {OnyxUpdate} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import * as API from '@libs/API';
import type {UpdateSubscriptionTypeParams} from '@libs/API/parameters';
import type {UpdateSubscriptionAddNewUsersAutomaticallyParams, UpdateSubscriptionAutoRenewParams, UpdateSubscriptionTypeParams} from '@libs/API/parameters';
import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
import type {SubscriptionType} from '@src/CONST';
import CONST from '@src/CONST';
import type {FeedbackSurveyOptionID, SubscriptionType} from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {OnyxData} from '@src/types/onyx/Request';

Expand All @@ -22,7 +22,9 @@ function updateSubscriptionType(type: SubscriptionType) {
key: ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION,
value: {
type,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
pendingFields: {
type: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
errors: null,
},
},
Expand All @@ -34,7 +36,9 @@ function updateSubscriptionType(type: SubscriptionType) {
key: ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION,
value: {
type,
pendingAction: null,
pendingFields: {
type: null,
},
errors: null,
},
},
Expand All @@ -46,7 +50,9 @@ function updateSubscriptionType(type: SubscriptionType) {
key: ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION,
value: {
type: type === CONST.SUBSCRIPTION.TYPE.ANNUAL ? CONST.SUBSCRIPTION.TYPE.PAYPERUSE : CONST.SUBSCRIPTION.TYPE.ANNUAL,
pendingAction: null,
pendingFields: {
type: null,
},
},
},
];
Expand All @@ -62,6 +68,112 @@ function updateSubscriptionType(type: SubscriptionType) {
});
}

function updateSubscriptionAutoRenew(autoRenew: boolean, disableAutoRenewReason?: FeedbackSurveyOptionID, disableAutoRenewAdditionalNote?: string) {
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION,
value: {
autoRenew,
pendingFields: {
autoRenew: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
errors: null,
},
},
];

const successData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION,
value: {
pendingFields: {
autoRenew: null,
},
errors: null,
},
},
];

const failureData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION,
value: {
autoRenew: !autoRenew,
pendingFields: {
autoRenew: null,
},
},
},
];

const parameters: UpdateSubscriptionAutoRenewParams = {
autoRenew,
disableAutoRenewReason,
disableAutoRenewAdditionalNote,
};

API.write(WRITE_COMMANDS.UPDATE_SUBSCRIPTION_AUTO_RENEW, parameters, {
optimisticData,
successData,
failureData,
});
}

function updateSubscriptionAddNewUsersAutomatically(addNewUsersAutomatically: boolean) {
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION,
value: {
addNewUsersAutomatically,
pendingFields: {
addNewUsersAutomatically: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
errors: null,
},
},
];

const successData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION,
value: {
pendingFields: {
addNewUsersAutomatically: null,
},
errors: null,
},
},
];

const failureData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION,
value: {
addNewUsersAutomatically: !addNewUsersAutomatically,
pendingFields: {
addNewUsersAutomatically: null,
},
},
},
];

const parameters: UpdateSubscriptionAddNewUsersAutomaticallyParams = {
addNewUsersAutomatically,
};

API.write(WRITE_COMMANDS.UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY, parameters, {
optimisticData,
successData,
failureData,
});
}

function updateSubscriptionSize(newSubscriptionSize: number, currentSubscriptionSize: number) {
const onyxData: OnyxData = {
optimisticData: [
Expand Down Expand Up @@ -119,4 +231,4 @@ function clearUpdateSubscriptionSizeError() {
});
}

export {openSubscriptionPage, updateSubscriptionType, updateSubscriptionSize, clearUpdateSubscriptionSizeError};
export {openSubscriptionPage, updateSubscriptionAutoRenew, updateSubscriptionAddNewUsersAutomatically, updateSubscriptionSize, clearUpdateSubscriptionSizeError, updateSubscriptionType};
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import ScrollView from '@components/ScrollView';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import * as Subscription from '@userActions/Subscription';
import type {FeedbackSurveyOptionID} from '@src/CONST';

function DisableAutoRenewSurveyPage() {
const {translate} = useLocalize();
const styles = useThemeStyles();

const handleSubmit = () => {
// TODO API call to submit feedback will be implemented in next phase
const handleSubmit = (key: FeedbackSurveyOptionID, additionalNote?: string) => {
Subscription.updateSubscriptionAutoRenew(false, key, additionalNote);
Navigation.goBack();
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function SubscriptionDetails() {
<Text style={[styles.textLabelSupporting, styles.mt2]}>{translate('subscription.details.zeroCommitment')}</Text>
</View>
) : (
<OfflineWithFeedback pendingAction={privateSubscription?.pendingAction}>
<OfflineWithFeedback pendingAction={privateSubscription?.pendingFields?.type}>
<OptionsPicker
options={options}
selectedOption={privateSubscription?.type ?? CONST.SUBSCRIPTION.TYPE.ANNUAL}
Expand Down
Loading

0 comments on commit 86a2e3d

Please sign in to comment.