Skip to content
Open
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 src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,7 @@ const CONST = {
DEFAULT_LETTER_AVATARS: 'defaultLetterAvatars',
NETSUITE_OAUTH: 'netSuiteOAuth',
CONCIERGE_RESPOND_IN_THREAD: 'conciergeRespondInThread',
TRAVEL_CODING_SYNC: 'travelCodingSync',
},
BUTTON_STATES: {
DEFAULT: 'default',
Expand Down
4 changes: 4 additions & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6135,6 +6135,10 @@ _Für ausführlichere Anweisungen [besuchen Sie unsere Hilfeseite](${CONST.NETSU
bookOrManageYourTrip: {title: 'Reisebuchung', subtitle: 'Glückwunsch! Du kannst in diesem Arbeitsbereich jetzt Reisen buchen und verwalten.', ctaText: 'Reisen verwalten'},
settings: {
autoAddTripName: {title: 'Reisenamen zu Ausgaben hinzufügen', subtitle: 'Reisenamen für in Expensify gebuchte Reisen automatisch zu Spesenbeschreibungen hinzufügen.'},
codingSync: {
title: 'Codierung mit Expensify Travel synchronisieren',
subtitle: 'Kategorien, Tags und Berichtsfelder dieses Arbeitsbereichs an Expensify Travel übertragen, damit Reisende sie beim Buchen beantworten.',
},
},
travelInvoicing: {
travelBookingSection: {
Expand Down
5 changes: 5 additions & 0 deletions src/languages/el.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6269,6 +6269,11 @@ _Για πιο αναλυτικές οδηγίες, [επισκεφθείτε τ
title: 'Προσθέστε ονόματα ταξιδιών στις δαπάνες',
subtitle: 'Προσθέτετε αυτόματα τα ονόματα ταξιδιών στις περιγραφές εξόδων για ταξίδια που κλείνονται στο Expensify.',
},
codingSync: {
title: 'Συγχρονισμός κωδικοποίησης με το Expensify Travel',
subtitle:
'Σπρώξτε τις κατηγορίες, τις ετικέτες και τα πεδία αναφοράς αυτού του χώρου εργασίας στο Expensify Travel, ώστε οι ταξιδιώτες να τα απαντούν κατά την ώρα της κράτησης.',
},
},
travelInvoicing: {
travelBookingSection: {
Expand Down
4 changes: 4 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6225,6 +6225,10 @@ const translations = {
title: 'Add trip names to expenses',
subtitle: 'Automatically add trip names to expense descriptions for travel booked in Expensify.',
},
codingSync: {
title: 'Sync coding to Expensify Travel',
subtitle: "Push this workspace's categories, tags, and report fields to Expensify Travel so travelers answer them at booking time.",
},
},
travelInvoicing: {
travelBookingSection: {
Expand Down
5 changes: 5 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6013,6 +6013,11 @@ ${amount} para ${merchant} - ${date}`,
title: 'Añadir nombres de viajes a los gastos',
subtitle: 'Añade automáticamente los nombres de viajes a las descripciones de los gastos reservados en Expensify.',
},
codingSync: {
title: 'Sincronizar codificación con Expensify Travel',
subtitle:
'Envía las categorías, etiquetas y campos de informe de este espacio de trabajo a Expensify Travel para que los viajeros los completen en el momento de la reserva.',
},
},
travelInvoicing: {
travelBookingSection: {
Expand Down
5 changes: 5 additions & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6156,6 +6156,11 @@ _Pour des instructions plus détaillées, [visitez notre site d’aide](${CONST.
title: 'Ajouter des noms de voyage aux dépenses',
subtitle: 'Ajouter automatiquement les noms de voyage aux descriptions des dépenses pour les voyages réservés dans Expensify.',
},
codingSync: {
title: 'Synchroniser le codage avec Expensify Travel',
subtitle:
'Envoyez les catégories, tags et champs de note de frais de cet espace de travail vers Expensify Travel pour que les voyageurs y répondent au moment de la réservation.',
},
},
travelInvoicing: {
travelBookingSection: {
Expand Down
5 changes: 5 additions & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6109,6 +6109,11 @@ _Per istruzioni più dettagliate, [visita il nostro sito di assistenza](${CONST.
title: 'Aggiungi nomi di viaggi alle spese',
subtitle: 'Aggiungi automaticamente i nomi dei viaggi alle descrizioni delle spese per i viaggi prenotati in Expensify.',
},
codingSync: {
title: 'Sincronizza la codifica con Expensify Travel',
subtitle:
'Invia le categorie, i tag e i campi di rendiconto di questo spazio di lavoro a Expensify Travel così che chi viaggia li compili al momento della prenotazione.',
},
},
travelInvoicing: {
travelBookingSection: {
Expand Down
8 changes: 7 additions & 1 deletion src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6035,7 +6035,13 @@ _詳しい手順については、[ヘルプサイトをご覧ください](${CO
ctaText: 'リクエストを送信しました',
},
bookOrManageYourTrip: {title: '出張予約', subtitle: 'おめでとうございます!このワークスペースで旅行の予約と管理を行う準備が整いました。', ctaText: '出張を管理'},
settings: {autoAddTripName: {title: '経費に出張名を追加', subtitle: 'Expensifyで予約した出張について、経費の説明に出張名を自動的に追加します。'}},
settings: {
autoAddTripName: {title: '経費に出張名を追加', subtitle: 'Expensifyで予約した出張について、経費の説明に出張名を自動的に追加します。'},
codingSync: {
title: 'コーディングを Expensify Travel と同期する',
subtitle: 'このワークスペースのカテゴリ、タグ、レポートフィールドを Expensify Travel にプッシュして、出張者が予約時にそれらに回答できるようにします。',
},
},
travelInvoicing: {
travelBookingSection: {
title: '出張予約',
Expand Down
4 changes: 4 additions & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6099,6 +6099,10 @@ _Voor meer gedetailleerde instructies, [bezoek onze help-site](${CONST.NETSUITE_
},
settings: {
autoAddTripName: {title: 'Reisnamen aan uitgaven toevoegen', subtitle: 'Voeg automatisch reisnamen toe aan onkostomemo’s voor reizen die in Expensify zijn geboekt.'},
codingSync: {
title: 'Synchroniseer codering met Expensify Travel',
subtitle: 'Push de categorieën, tags en rapportvelden van deze workspace naar Expensify Travel zodat reizigers ze bij het boeken invullen.',
},
},
travelInvoicing: {
travelBookingSection: {
Expand Down
4 changes: 4 additions & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6076,6 +6076,10 @@ _Aby uzyskać bardziej szczegółowe instrukcje, [odwiedź naszą stronę pomocy
},
settings: {
autoAddTripName: {title: 'Dodaj nazwy podróży do wydatków', subtitle: 'Automatycznie dodawaj nazwy podróży do opisów wydatków za podróże zarezerwowane w Expensify.'},
codingSync: {
title: 'Synchronizuj kodowanie z Expensify Travel',
subtitle: 'Przekaż kategorie, tagi i pola raportu tego workspace’u do Expensify Travel, żeby podróżujący odpowiadali na nie podczas rezerwacji.',
},
},
travelInvoicing: {
travelBookingSection: {
Expand Down
4 changes: 4 additions & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6098,6 +6098,10 @@ _Para instruções mais detalhadas, [visite nossa central de ajuda](${CONST.NETS
title: 'Adicionar nomes de viagem às despesas',
subtitle: 'Adicione automaticamente os nomes das viagens às descrições das despesas para viagens reservadas no Expensify.',
},
codingSync: {
title: 'Sincronizar codificação com o Expensify Travel',
subtitle: 'Envie as categorias, tags e campos de relatório deste workspace para o Expensify Travel para que os viajantes os respondam no momento da reserva.',
},
},
travelInvoicing: {
travelBookingSection: {
Expand Down
5 changes: 4 additions & 1 deletion src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5901,7 +5901,10 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM
ctaText: '请求已发送',
},
bookOrManageYourTrip: {title: '差旅预订', subtitle: '恭喜!您现在可以在此工作区预订和管理差旅了。', ctaText: '管理差旅'},
settings: {autoAddTripName: {title: '将行程名称添加到报销单', subtitle: '为在 Expensify 中预订的行程,自动将行程名称添加到报销事由描述中。'}},
settings: {
autoAddTripName: {title: '将行程名称添加到报销单', subtitle: '为在 Expensify 中预订的行程,自动将行程名称添加到报销事由描述中。'},
codingSync: {title: '将编码同步到 Expensify Travel', subtitle: '将此工作区的类别、标签和报表字段推送到 Expensify Travel,以便出行人能在预订时填写。'},
},
travelInvoicing: {
travelBookingSection: {
title: '差旅预订',
Expand Down
40 changes: 27 additions & 13 deletions src/libs/actions/Policy/Travel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import type {EnablePolicyTravelParams, SetPolicyTravelSettingsParams} from '@lib
import {WRITE_COMMANDS} from '@libs/API/types';
import * as ErrorUtils from '@libs/ErrorUtils';
import getIsNarrowLayout from '@libs/getIsNarrowLayout';
import {getObjectKeys} from '@libs/ObjectUtils';
import {goBackWhenEnableFeature} from '@libs/PolicyUtils';

import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type * as OnyxTypes from '@src/types/onyx';
import type {ErrorFields, PendingFields} from '@src/types/onyx/OnyxCommon';
import type {OnyxData} from '@src/types/onyx/Request';

import type {OnyxEntry} from 'react-native-onyx';
Expand Down Expand Up @@ -72,16 +74,33 @@ function setPolicyTravelSettings(policy: OnyxEntry<OnyxTypes.Policy>, settings:
const policyID = policy.id;
const previousTravelSettings = policy?.travelSettings;

// Revert each changed key to its prior value, defaulting to null so a key that was absent
// before the optimistic update (e.g. a toggle that reads as off) is cleared by the merge
// instead of being left at its optimistic value.
const revertedSettings: Partial<OnyxTypes.WorkspaceTravelSettings> = {};

// Pending and error state is tracked per setting so that updating one setting does not
// put every other travel setting's row into a pending or failed state.
const pendingSettings: PendingFields<keyof OnyxTypes.WorkspaceTravelSettings> = {};
const clearedSettingFields: Record<string, null> = {};
const settingErrors: ErrorFields = {};

for (const key of getObjectKeys(settings)) {
(revertedSettings as Record<string, unknown>)[key] = previousTravelSettings?.[key] ?? null;
pendingSettings[key] = CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE;
clearedSettingFields[key] = null;
settingErrors[key] = ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage');
}

const onyxData: OnyxData<typeof ONYXKEYS.COLLECTION.POLICY> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
travelSettings: {...previousTravelSettings, ...settings},
pendingFields: {
travelSettings: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
pendingFields: pendingSettings,
errorFields: clearedSettingFields,
},
Comment thread
ishpaul777 marked this conversation as resolved.
},
],
Expand All @@ -90,9 +109,8 @@ function setPolicyTravelSettings(policy: OnyxEntry<OnyxTypes.Policy>, settings:
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
pendingFields: {
travelSettings: null,
},
pendingFields: clearedSettingFields,
errorFields: clearedSettingFields,
},
},
],
Expand All @@ -101,13 +119,9 @@ function setPolicyTravelSettings(policy: OnyxEntry<OnyxTypes.Policy>, settings:
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
travelSettings: previousTravelSettings,
pendingFields: {
travelSettings: null,
},
errorFields: {
travelSettings: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'),
},
travelSettings: revertedSettings,
pendingFields: clearedSettingFields,
errorFields: settingErrors,
},
},
],
Expand Down
29 changes: 28 additions & 1 deletion src/pages/workspace/travel/BookOrManageYourTrip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import usePolicyFeatureWriteAccess from '@hooks/usePolicyFeatureWriteAccess';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';

import {clearPolicyErrorField} from '@libs/actions/Policy/Policy';
import {setPolicyTravelSettings} from '@libs/actions/Policy/Travel';
import {openTravelDotLink} from '@libs/openTravelDotLink';

Expand Down Expand Up @@ -45,6 +46,13 @@ function GetStartedTravel({policyID}: GetStartedTravelProps) {
setPolicyTravelSettings(policy, {autoAddTripName: enabled});
};

const isCodingSyncBetaEnabled = isBetaEnabled(CONST.BETAS.TRAVEL_CODING_SYNC);
const isCodingSyncEnabled = policy?.travelSettings?.isCodingSyncEnabled ?? false;

const toggleCodingSync = (enabled: boolean) => {
setPolicyTravelSettings(policy, {isCodingSyncEnabled: enabled});
};

const handleManageTravel = () => {
if (isPreventSpotnanaTravelEnabled) {
showConfirmModal({
Expand Down Expand Up @@ -92,9 +100,28 @@ function GetStartedTravel({policyID}: GetStartedTravelProps) {
disabled={!canWriteMoreFeatures}
disabledAction={withReadOnlyFallback()}
showLockIcon={!canWriteMoreFeatures}
pendingAction={policy?.pendingFields?.travelSettings}
pendingAction={policy?.pendingFields?.autoAddTripName}
errors={policy?.errorFields?.autoAddTripName ?? undefined}
onCloseError={() => clearPolicyErrorField(policyID, 'autoAddTripName')}
wrapperStyle={styles.mt3}
/>
{isCodingSyncBetaEnabled && (
<ToggleSettingOptionRow
title={translate('workspace.moreFeatures.travel.settings.codingSync.title')}
subtitle={translate('workspace.moreFeatures.travel.settings.codingSync.subtitle')}
shouldPlaceSubtitleBelowSwitch
switchAccessibilityLabel={translate('workspace.moreFeatures.travel.settings.codingSync.title')}
isActive={isCodingSyncEnabled}
onToggle={toggleCodingSync}
Comment thread
ishpaul777 marked this conversation as resolved.
disabled={!canWriteMoreFeatures}
disabledAction={withReadOnlyFallback()}
showLockIcon={!canWriteMoreFeatures}
pendingAction={policy?.pendingFields?.isCodingSyncEnabled}
errors={policy?.errorFields?.isCodingSyncEnabled ?? undefined}
onCloseError={() => clearPolicyErrorField(policyID, 'isCodingSyncEnabled')}
wrapperStyle={styles.mt3}
/>
)}
</Section>
<WorkspaceTravelInvoicingSection policyID={policyID} />
</>
Expand Down
2 changes: 1 addition & 1 deletion src/types/onyx/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3164,7 +3164,7 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback<
/** Whether the policy requires purchases to be on a company card */
requireCompanyCardsEnabled?: boolean;
} & Partial<PendingJoinRequestPolicy>,
'addWorkspaceRoom' | keyof ACHAccount | keyof Attributes | 'isHREnabled' | 'isTimeTrackingEnabled' | 'timeTrackingDefaultRate'
'addWorkspaceRoom' | keyof ACHAccount | keyof Attributes | keyof WorkspaceTravelSettings | 'isHREnabled' | 'isTimeTrackingEnabled' | 'timeTrackingDefaultRate'
>;

/** Stages of policy connection sync */
Expand Down
3 changes: 3 additions & 0 deletions src/types/onyx/TravelSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ type WorkspaceTravelSettings = {
/** Whether to automatically add trip names to expense descriptions during travel */
autoAddTripName?: boolean;

/** Whether the workspace's categories, tags and report fields are sent to Spotnana as booking questions. Absent means off. */
isCodingSyncEnabled?: boolean;
Comment thread
ishpaul777 marked this conversation as resolved.

/** Legal entity tax ID, collected during Travel enablement on non-USD workspaces so Solutions can provision a DK number */
taxID?: string;
};
Expand Down
Loading
Loading