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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,7 @@ const CONST = {
BULK_SUBMIT_APPROVE_PAY: 'bulkSubmitApprovePay',
VENDOR_MATCHING: 'vendorMatching',
BUSINESS_CENTRAL: 'businessCentral',
EXACT_ONLINE: 'exactOnline2026',
COMMUTER_EXCLUSIONS: 'commuterExclusions',
COMMUTER_EXCLUSIONS_ARRANGEMENTS: 'commuterExclusionsArrangements',
MULTIPLE_APPROVERS: 'multipleApprovers',
Expand Down Expand Up @@ -5031,6 +5032,7 @@ const CONST = {
CAMPFIRE: 'campfire',
ZOHO_BOOKS: 'zohoBooks',
BUSINESS_CENTRAL: 'businessCentral',
EXACT_ONLINE: 'exactOnline',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NAB: Do we want to show Exact Online in the onboarding flow (ONBOARDING_ACCOUNTING_MAPPING)?

Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not necessary. Its defacto covered by other + we have other fully integrated accounting software not in that list.

GUSTO: 'gusto',
ZENEFITS: 'zenefits',
MERGE_HR: 'merge_hris',
Expand Down Expand Up @@ -5069,6 +5071,7 @@ const CONST = {
campfire: 'Campfire',
zohoBooks: 'Zoho Books',
businessCentral: 'Dynamics 365 Business Central',
exactOnline: 'Exact Online',
gusto: 'Gusto',
billCom: 'Bill.com',
zenefits: 'TriNet',
Expand Down Expand Up @@ -10267,6 +10270,7 @@ const CONST = {
},
ACCOUNTING: {
SETUP_BUTTON: 'WorkspaceAccounting-SetupButton',
EXACT_ONLINE_WAITLIST_BUTTON: 'WorkspaceAccounting-ExactOnlineWaitlistButton',
CARD_SECTION_ADD_BUTTON: 'WorkspaceAccounting-CardSectionAddButton',
THREE_DOT_MENU: 'WorkspaceAccounting-ThreeDotMenu',
},
Expand Down
4 changes: 4 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ const ONYXKEYS = {

/** NVP keys */

/** UTC signup timestamp for the account's Exact Online waitlist membership */
NVP_EXACT_ONLINE_WAITLIST: 'nvp_expensify_exactOnlineWaitlist',

/** This NVP contains list of at most 5 recent attendees */
NVP_RECENT_ATTENDEES: 'nvp_expensify_recentAttendees',

Expand Down Expand Up @@ -1784,6 +1787,7 @@ type OnyxValuesMapping = {
// The value of this nvp is a string representation of the date when the block expires, or an empty string if the user is not blocked
[ONYXKEYS.NVP_BLOCKED_FROM_CHAT]: string;
[ONYXKEYS.NVP_PRIVATE_PUSH_NOTIFICATION_ID]: string;
[ONYXKEYS.NVP_EXACT_ONLINE_WAITLIST]: string;
[ONYXKEYS.NVP_RECENT_ATTENDEES]: Attendee[];
[ONYXKEYS.NVP_TRY_FOCUS_MODE]: boolean;
[ONYXKEYS.NVP_DISMISSED_HOLD_USE_EXPLANATION]: boolean;
Expand Down
2 changes: 2 additions & 0 deletions src/components/Icon/chunks/expensify-icons.chunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ import CircleSlash from '@assets/images/integrationicons/circle-slash.svg';
import ClaudeSquare from '@assets/images/integrationicons/claude-icon-square.svg';
import CursorSquare from '@assets/images/integrationicons/cursor-icon-square.svg';
import DualEntrySquare from '@assets/images/integrationicons/dualentry-icon-square.svg';
import ExactOnlineSquare from '@assets/images/integrationicons/exact-online-icon-square.svg';
import NetSuiteExport from '@assets/images/integrationicons/export/netsuite-icon.svg';
import QBOExport from '@assets/images/integrationicons/export/qbo-icon.svg';
import SageIntacctExport from '@assets/images/integrationicons/export/sage-intacct-icon.svg';
Expand Down Expand Up @@ -505,6 +506,7 @@ const Expensicons = {
ReceiptMultiple,
RilletSquare,
DualEntrySquare,
ExactOnlineSquare,
Rotate,
RotateLeft,
Scan,
Expand Down
3 changes: 2 additions & 1 deletion src/languages/TranslationTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ type PersonalRulesModifiedFields = PolicyRulesModifiedFields & {
reportName?: string;
};

type ConnectionName = ValueOf<typeof CONST.POLICY.CONNECTIONS.NAME>;
// Exact Online only has a waitlist until its connector is released.
type ConnectionName = Exclude<ValueOf<typeof CONST.POLICY.CONNECTIONS.NAME>, typeof CONST.POLICY.CONNECTIONS.NAME.EXACT_ONLINE>;
type AllConnectionName = ConnectionName;
type PolicyConnectionSyncStage = ValueOf<typeof CONST.POLICY.CONNECTIONS.SYNC_STAGE_NAME>;
type SageIntacctMappingName = ValueOf<typeof CONST.SAGE_INTACCT_CONFIG.MAPPINGS>;
Expand Down
6 changes: 6 additions & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7468,6 +7468,12 @@ Der Control-Tarif beginnt bei 9 $ pro aktivem Mitglied und Monat.`,
errorODIntegration: (oldDotPolicyConnectionsURL: string) =>
`Bei einer in Expensify Classic eingerichteten Verbindung ist ein Fehler aufgetreten. [Wechsle zu Expensify Classic, um dieses Problem zu beheben.](${oldDotPolicyConnectionsURL})`,
goToODToSettings: 'Wechsle zu Expensify Classic, um deine Einstellungen zu verwalten.',
exactOnline: {
comingSoon: 'Demnächst verfügbar',
joinWaitlist: 'Warteliste beitreten',
onWaitlist: 'Sie stehen auf der Warteliste',
waitlistDescription: 'Concierge sendet Ihnen eine Nachricht, sobald diese Integration bereit ist, und erklärt Ihnen, wie Sie die Verbindung herstellen.',
},
setup: 'Verbinden',
connectToSandbox: 'Mit Sandbox verbinden',
lastSync: (relativeDate: string) => `Zuletzt synchronisiert ${relativeDate}`,
Expand Down
6 changes: 6 additions & 0 deletions src/languages/el.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7601,6 +7601,12 @@ _Για πιο αναλυτικές οδηγίες, [επισκεφθείτε τ
errorODIntegration: (oldDotPolicyConnectionsURL: string) =>
`Προέκυψε σφάλμα με μια σύνδεση που έχει ρυθμιστεί στο Expensify Classic. [Μεταβείτε στο Expensify Classic για να διορθώσετε αυτό το ζήτημα.](${oldDotPolicyConnectionsURL})`,
goToODToSettings: 'Μεταβείτε στο Expensify Classic για να διαχειριστείτε τις ρυθμίσεις σας.',
exactOnline: {
comingSoon: 'Έρχεται σύντομα',
joinWaitlist: 'Εγγραφείτε στη λίστα αναμονής',
onWaitlist: 'Είστε σε λίστα αναμονής',
waitlistDescription: 'Ο Concierge θα σας στείλει ένα μήνυμα για να σας ενημερώσει πότε θα είναι έτοιμη αυτή η ενσωμάτωση και πώς να τη συνδέσετε.',
},
setup: 'Σύνδεση',
connectToSandbox: 'Σύνδεση στο sandbox',
lastSync: (relativeDate: string) => `Τελευταίος συγχρονισμός ${relativeDate}`,
Expand Down
6 changes: 6 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7865,6 +7865,12 @@ const translations = {
errorODIntegration: (oldDotPolicyConnectionsURL: string) =>
`There's an error with a connection that's been set up in Expensify Classic. [Go to Expensify Classic to fix this issue.](${oldDotPolicyConnectionsURL})`,
goToODToSettings: 'Go to Expensify Classic to manage your settings.',
exactOnline: {
comingSoon: 'Coming soon',
joinWaitlist: 'Join waitlist',
onWaitlist: 'You’re on the waitlist',
waitlistDescription: 'Concierge will send you a message to let you know when this integration is ready and how to connect.',
},
setup: 'Connect',
connectToSandbox: 'Connect to sandbox',
lastSync: (relativeDate: string) => `Last synced ${relativeDate}`,
Expand Down
6 changes: 6 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7266,6 +7266,12 @@ El plan Controlar empieza en 9 $ por miembro activo al mes.`,
errorODIntegration: (oldDotPolicyConnectionsURL) =>
`Hay un error con una conexión que se ha configurado en Expensify Classic. [Ve a Expensify Classic para solucionar este problema.](${oldDotPolicyConnectionsURL})`,
goToODToSettings: 'Ve a Expensify Classic para gestionar tus configuraciones.',
exactOnline: {
comingSoon: 'Próximamente',
joinWaitlist: 'Unirse a la lista de espera',
onWaitlist: 'Estás en la lista de espera',
waitlistDescription: 'Concierge te enviará un mensaje para avisarte cuando esta integración esté lista y cómo conectarla.',
},
setup: 'Configurar',
connectToSandbox: 'Conectar con Sandbox',
lastSync: (relativeDate) => `Recién sincronizado ${relativeDate}`,
Expand Down
6 changes: 6 additions & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7488,6 +7488,12 @@ Le forfait Control commence à 9 $ par Membre actif et par mois.`,
errorODIntegration: (oldDotPolicyConnectionsURL: string) =>
`Une erreur s’est produite avec une connexion configurée dans Expensify Classic. [Accédez à Expensify Classic pour corriger ce problème.](${oldDotPolicyConnectionsURL})`,
goToODToSettings: 'Accédez à Expensify Classic pour gérer vos paramètres.',
exactOnline: {
comingSoon: 'Bientôt disponible',
joinWaitlist: 'Rejoindre la liste d’attente',
onWaitlist: 'Vous êtes sur la liste d’attente',
waitlistDescription: 'Concierge vous enverra un message pour vous informer lorsque cette intégration sera prête et vous expliquer comment la connecter.',
},
setup: 'Connecter',
connectToSandbox: 'Se connecter à Sandbox',
lastSync: (relativeDate: string) => `Dernière synchronisation ${relativeDate}`,
Expand Down
6 changes: 6 additions & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7425,6 +7425,12 @@ Il piano Control parte da 9 $ al mese per ogni membro attivo.`,
errorODIntegration: (oldDotPolicyConnectionsURL: string) =>
`Si è verificato un errore con una connessione configurata in Expensify Classic. [Vai a Expensify Classic per risolvere questo problema.](${oldDotPolicyConnectionsURL})`,
goToODToSettings: 'Vai a Expensify Classic per gestire le tue impostazioni.',
exactOnline: {
comingSoon: 'Presto in arrivo',
joinWaitlist: 'Unisciti alla lista d’attesa',
onWaitlist: 'Sei in lista d’attesa',
waitlistDescription: 'Concierge ti invierà un messaggio per farti sapere quando questa integrazione sarà pronta e come collegarla.',
},
setup: 'Connetti',
connectToSandbox: 'Connetti alla sandbox',
lastSync: (relativeDate: string) => `Ultima sincronizzazione ${relativeDate}`,
Expand Down
6 changes: 6 additions & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7334,6 +7334,12 @@ Control プランは、アクティブメンバー1人あたり月額 $9 から
errorODIntegration: (oldDotPolicyConnectionsURL: string) =>
`Expensify Classic で設定されている接続にエラーがあります。[この問題を解決するには Expensify Classic に移動してください。](${oldDotPolicyConnectionsURL})`,
goToODToSettings: '設定を管理するには、Expensify Classic に移動してください。',
exactOnline: {
comingSoon: '近日公開予定',
joinWaitlist: 'ウェイトリストに参加',
onWaitlist: '順番待ちリストに登録されています',
waitlistDescription: 'この連携の準備が整い、接続方法が決まりましたら、Concierge からメッセージでお知らせします。',
},
setup: '接続',
connectToSandbox: 'Sandbox に接続',
lastSync: (relativeDate: string) => `最終同期:${relativeDate}`,
Expand Down
6 changes: 6 additions & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7408,6 +7408,12 @@ Het Control-abonnement begint bij $9 per actieve deelnemer per maand.`,
errorODIntegration: (oldDotPolicyConnectionsURL: string) =>
`Er is een fout opgetreden met een verbinding die is ingesteld in Expensify Classic. [Ga naar Expensify Classic om dit probleem op te lossen.](${oldDotPolicyConnectionsURL})`,
goToODToSettings: 'Ga naar Expensify Classic om je instellingen te beheren.',
exactOnline: {
comingSoon: 'Binnenkort beschikbaar',
joinWaitlist: 'Aanmelden voor wachtlijst',
onWaitlist: 'Je staat op de wachtlijst',
waitlistDescription: 'Concierge stuurt je een bericht om je te laten weten wanneer deze integratie klaar is en hoe je verbinding kunt maken.',
},
setup: 'Verbinden',
connectToSandbox: 'Verbinden met sandbox',
lastSync: (relativeDate: string) => `Laatst gesynchroniseerd ${relativeDate}`,
Expand Down
6 changes: 6 additions & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7434,6 +7434,12 @@ Plan Control zaczyna się od 9 USD za aktywnego członka miesięcznie.`,
errorODIntegration: (oldDotPolicyConnectionsURL: string) =>
`Wystąpił błąd z połączeniem skonfigurowanym w Expensify Classic. [Przejdź do Expensify Classic, aby rozwiązać ten problem.](${oldDotPolicyConnectionsURL})`,
goToODToSettings: 'Przejdź do Expensify Classic, aby zarządzać swoimi ustawieniami.',
exactOnline: {
comingSoon: 'Wkrótce dostępne',
joinWaitlist: 'Dołącz do listy oczekujących',
onWaitlist: 'Jesteś na liście oczekujących',
waitlistDescription: 'Concierge wyśle ci wiadomość, żeby dać znać, kiedy ta integracja będzie gotowa i jak ją połączyć.',
},
setup: 'Połącz',
connectToSandbox: 'Połącz z sandboxem',
lastSync: (relativeDate: string) => `Ostatnia synchronizacja ${relativeDate}`,
Expand Down
6 changes: 6 additions & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7410,6 +7410,12 @@ O plano Control começa em US$ 9 por membro ativo por mês.`,
errorODIntegration: (oldDotPolicyConnectionsURL: string) =>
`Há um erro em uma conexão configurada no Expensify Classic. [Acesse o Expensify Classic para corrigir esse problema.](${oldDotPolicyConnectionsURL})`,
goToODToSettings: 'Vá para o Expensify Classic para gerenciar suas configurações.',
exactOnline: {
comingSoon: 'Em breve',
joinWaitlist: 'Entrar na lista de espera',
onWaitlist: 'Você está na lista de espera',
waitlistDescription: 'O Concierge vai enviar uma mensagem para avisar quando essa integração estiver pronta e como conectá-la.',
},
setup: 'Conectar',
connectToSandbox: 'Conectar ao sandbox',
lastSync: (relativeDate: string) => `Última sincronização ${relativeDate}`,
Expand Down
6 changes: 6 additions & 0 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7148,6 +7148,12 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM
},
errorODIntegration: (oldDotPolicyConnectionsURL: string) => `Expensify Classic 中已设置的某个连接出错。[前往 Expensify Classic 解决此问题](${oldDotPolicyConnectionsURL})`,
goToODToSettings: '前往 Expensify Classic 管理您的设置。',
exactOnline: {
comingSoon: '即将推出',
joinWaitlist: '加入候补名单',
onWaitlist: '您在候补名单中',
waitlistDescription: '当此集成准备就绪并可连接时,Concierge 会向你发送消息通知你并说明如何连接。',
},
setup: '连接',
connectToSandbox: '连接到沙盒',
lastSync: (relativeDate: string) => `上次同步于 ${relativeDate}`,
Expand Down
1 change: 1 addition & 0 deletions src/libs/ExportOnyxState/masking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ const safeOnyxKeys = new Set<string>([
ONYXKEYS.NVP_DISMISSED_REJECT_USE_EXPLANATION,
ONYXKEYS.NVP_DISMISSED_TRIAL_PAYMENT_REMINDER,
ONYXKEYS.NVP_EMPTY_REPORTS_CONFIRMATION_DISMISSED,
ONYXKEYS.NVP_EXACT_ONLINE_WAITLIST,
ONYXKEYS.NVP_HAS_SEEDED_MY_EXPENSES_SEARCH,
ONYXKEYS.NVP_HAS_SEEN_FOR_YOU_TODO,
ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING,
Expand Down
51 changes: 51 additions & 0 deletions src/libs/actions/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,55 @@ function setNameValuePair<TKey extends OnyxKey>(name: TKey, value: SetNameValueP
});
}

function joinExactOnlineWaitlist() {
const signupTimestamp = DateUtils.getDBTime();
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.ACCOUNT>> = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.ACCOUNT,
value: {
pendingFields: {exactOnlineWaitlist: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD},
errorFields: {exactOnlineWaitlist: null},
},
},
];
// The confirmation modal must not treat a queued signup as confirmed membership.
const successData: Array<OnyxUpdate<typeof ONYXKEYS.NVP_EXACT_ONLINE_WAITLIST | typeof ONYXKEYS.ACCOUNT>> = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.NVP_EXACT_ONLINE_WAITLIST,
value: signupTimestamp,
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.ACCOUNT,
value: {pendingFields: {exactOnlineWaitlist: null}},
},
];
const failureData: Array<OnyxUpdate<typeof ONYXKEYS.NVP_EXACT_ONLINE_WAITLIST | typeof ONYXKEYS.ACCOUNT>> = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.NVP_EXACT_ONLINE_WAITLIST,
value: '',
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.ACCOUNT,
value: {
pendingFields: {exactOnlineWaitlist: null},
errorFields: {exactOnlineWaitlist: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')},
},
},
];

// The queued request keeps this timestamp when it retries, preserving the original signup time.
API.write(WRITE_COMMANDS.SET_NAME_VALUE_PAIR, {name: ONYXKEYS.NVP_EXACT_ONLINE_WAITLIST, value: signupTimestamp}, {optimisticData, successData, failureData});
}

function clearExactOnlineWaitlistError() {
Onyx.merge(ONYXKEYS.ACCOUNT, {errorFields: {exactOnlineWaitlist: null}});
}

function dismissMarketingWindow(updateKey: string) {
const optimisticData: AnyOnyxUpdate[] = [
{
Expand Down Expand Up @@ -2039,6 +2088,8 @@ export {
clearDraftCustomStatus,
requestRefund,
setNameValuePair,
joinExactOnlineWaitlist,
clearExactOnlineWaitlistError,
setSubmitMigrationModalShown,
clearUnvalidatedNewContactMethodAction,
clearPendingContactActionErrors,
Expand Down
Loading
Loading