Expensify / App

Welcome to New Expensify: a complete re-imagination of financial collaboration, centered around chat. Help us build the next generation of Expensify by sharing feedback and contributing to the code.
https://new.expensify.com
MIT License
3.11k stars 2.61k forks source link

[#Wave-Control - Add Sage Intacct] Settings Configuration in NewDot: Import #43533

Open yuwenmemon opened 3 weeks ago

yuwenmemon commented 3 weeks ago

Tracking GH: https://github.com/Expensify/Expensify/issues/388780

Design doc section: https://docs.google.com/document/d/1k3ZFw8KB55yPUSCG6KYZlwpwEtmRt3eUshwxs7bZq5I/edit#heading=h.vc9skc4t3y4f


You will find in the following issue the pseudocode for the different flows. Use them as a guide in your implementation.

Import flow

Main page

function SageIntacctImportPage({policy}: WithPolicyProps) {
    const {mappings, pendingFields, errorFields, tax} = policy?.connections?.intacct?.config ?? {};

    const currentSageIntacctOrganizationName = useMemo(() => getCurrentSageIntacctOrganizationName(policy ?? undefined), [policy]);

    const userDimensionsSection = useMemo(
        () => ({
            action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_USER_DEFINED_DIMENSIONS.getRoute(policyID)),
            hasError: !!errorFields?.mappings.dimensions,
            title: mappings.dimensions.length ? translate('workspace.accounting.imported') : translate('workspace.sageIntacct.notImported'),
            pendingAction: pendingFields?.dimensions,
        }),
        [translate, errorFields?.dimensions, mappings.dimensions.length, pendingFields?.dimensions, policyID],
    );

    const sections = useMemo(
        () => [
            {
                description: translate('workspace.sageIntacct.billable'),
                action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_BILLABLE.getRoute(policyID)),
                title: mappings.syncItems ? translate('workspace.accounting.imported') : translate('workspace.sageIntacct.notImported'),
                pendingAction: pendingFields?.syncItems,
            },
            {
                description: translate('workspace.sageIntacct.departments'),
                action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_DEPARTMENTS.getRoute(policyID)),
                hasError: !!errorFields?.departments,
                title: mappings.departments === 'DEFAULT' ? translate('workspace.accounting.importTypes.DEFAULT') : translate(`workspace.accounting.importTypes.${mappings.departments}`),
                pendingAction: pendingFields?.departments,
            },
            {
                description: translate('workspace.sageIntacct.classes'),
                action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_CLASSES.getRoute(policyID)),
                hasError: !!errorFields?.classes,
                title: mappings.classes === 'DEFAULT' ? translate('workspace.accounting.importTypes.DEFAULT') : translate(`workspace.accounting.importTypes.${mappings.classes}`),
                pendingAction: pendingFields?.classes,
            },
            {
                description: translate('workspace.sageIntacct.locations'),
                action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_LOCATIONS.getRoute(policyID)),
                hasError: !!errorFields?.locations,
                title: mappings.locations === 'DEFAULT' ? translate('workspace.accounting.importTypes.DEFAULT') : translate(`workspace.accounting.importTypes.${mappings.locations}`),
                pendingAction: pendingFields?.locations,
            },
            {
                description: translate('workspace.sageIntacct.customers'),
                action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_CUSTOMERS.getRoute(policyID)),
                hasError: !!errorFields?.customers,
                title: mappings.customers === 'DEFAULT' ? translate('workspace.accounting.importTypes.DEFAULT') : translate(`workspace.accounting.importTypes.${mappings.customers}`),
                pendingAction: pendingFields?.customers,
            },
            {
                description: translate('workspace.sageIntacct.projects'),
                action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_PROJECTS.getRoute(policyID)),
                hasError: !!errorFields?.projects,
                title: mappings.projects === 'DEFAULT' ? translate('workspace.accounting.importTypes.DEFAULT') : translate(`workspace.accounting.importTypes.${mappings.projects}`),
                pendingAction: pendingFields?.projects,
            },
            {
                description: translate('workspace.accounting.taxes'),
                action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_TAXES.getRoute(policyID)),
                hasError: !!errorFields?.tax,
                title: tax.syncTax ? translate('workspace.accounting.imported') : translate('workspace.sageIntacct.notImported'),
                pendingAction: pendingFields?.tax,
            },
        ],
        [
        //... useMemo() dependencies
        ],
    );

    return (
        <ConnectionLayout
            displayName={SageIntacctImportPage.displayName}
            headerTitle="workspace.accounting.import"
            headerSubtitle={currentSageIntacctOrganizationName}
            accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN, CONST.POLICY.ACCESS_VARIANTS.PAID]}
            policyID={policyID}
            featureName={CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED}
            contentContainerStyle={styles.pb2}
            titleStyle={styles.ph5}
            connectionName={CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT}
        >
            <View style={[styles.flexRow, styles.mb4, styles.alignItemsCenter, styles.justifyContentBetween]}>
                <View style={styles.flex1}>
                    <Text fontSize={variables.fontSizeNormal}>{translate('workspace.sageIntacct.expenseTypes')}</Text>
                </View>
                <View style={[styles.flex1, styles.alignItemsEnd, styles.pl3]}>
                    <Switch
                        accessibilityLabel={translate('workspace.sageIntacct.expenseTypes')}
                        isOn
                        onToggle={() => {}}
                    />
                </View>
            </View>
            <OfflineWithFeedback key={translate('workspace.sageIntacct.billable')} pendingAction={pendingFields?.syncItems}>
                <View style={[styles.flexRow, styles.mb4, styles.alignItemsCenter, styles.justifyContentBetween]}>
                    <View style={styles.flex1}>
                        <Text fontSize={variables.fontSizeNormal}>{translate('workspace.sageIntacct.billable')}</Text>
                    </View>
                    <View style={[styles.flex1, styles.alignItemsEnd, styles.pl3]}>
                        <Switch
                            accessibilityLabel={translate('workspace.sageIntacct.billable')}
                            isOn={!!mappings.syncItems}
                            disabled
                            onToggle={(enabled) => {
                                Connections.updateSageIntacctBillable(policyID, enabled);
                            }}
                        />
                    </View>
                </View>
            </OfflineWithFeedback>
            {sections.map((section) => (
                <OfflineWithFeedback key={section.description} pendingAction={section.pendingAction}>
                    <MenuItemWithTopDescription
                        title={section.title}
                        description={section.description}
                        shouldShowRightIcon
                        onPress={section.action}
                        brickRoadIndicator={section.hasError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined}
                    />
                </OfflineWithFeedback>
            ))}
            <View style={[styles.flexRow, styles.mb4, styles.alignItemsCenter, styles.justifyContentBetween]}>
                <View style={styles.flex1}>
                    <Text fontSize={variables.fontSizeNormal}>{translate('workspace.sageIntacct.tax')}</Text>
                </View>
                <View style={[styles.flex1, styles.alignItemsEnd, styles.pl3]}>
                    <Switch
                        accessibilityLabel={translate('workspace.sageIntacct.tax')}
                        isOn={!!tax.syncTax}
                        onToggle={(enabled) => Connections.updateSageIntacctSyncTaxConfiguration(policyID, enabled)}
                    />
                </View>
                <Text fontSize={variables.fontSizeLabel} style={styles.textSupporting}>
                    {translate('workspace.sageIntacct.taxDescription')}
                </Text>
            </View>
            <OfflineWithFeedback key={userDimensionsSection.description} pendingAction={userDimensionsSection.pendingAction}>
                <MenuItem
                    title={userDimensionsSection.title}
                    shouldShowRightIcon
                    onPress={userDimensionsSection.action}
                    brickRoadIndicator={userDimensionsSection.hasError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined}
                />
            </OfflineWithFeedback>
        </ConnectionLayout>
    );
}

SageIntacctImportPage.displayName = 'PolicySageIntacctImportPage';

export default withPolicy(SageIntacctImportPage);
Issue OwnerCurrent Issue Owner: @hungvu193
melvin-bot[bot] commented 3 weeks ago

Triggered auto assignment to Contributor-plus team member for initial proposal review - @abdulrahuman5196 (External)

melvin-bot[bot] commented 3 weeks ago

Triggered auto assignment to @isabelastisser (NewFeature), see https://stackoverflowteams.com/c/expensify/questions/14418#:~:text=BugZero%20process%20steps%20for%20feature%20requests for more details. Please add this Feature request to a GH project, as outlined in the SO.

SzymczakJ commented 3 weeks ago

Hey! I’m Jakub Szymczak from Software Mansion, an expert agency, and I’d like to work on this issue!

SzymczakJ commented 3 weeks ago

Update: I'll start working on this issue once I put up a PR on https://github.com/Expensify/App/issues/43532. Posting this so you know about my priorities.

hungvu193 commented 2 weeks ago

Thanks for your update 👍

SzymczakJ commented 2 weeks ago

I'll be starting to work on this task tomorrow as I'm almost done with the Sage Intacct connection task.

melvin-bot[bot] commented 2 weeks ago

@yuwenmemon, @hungvu193, @isabelastisser, @SzymczakJ Whoops! This issue is 2 days overdue. Let's get this updated quick!

hungvu193 commented 2 weeks ago

Can we put this on hold for https://github.com/Expensify/App/issues/43532 🤔 so it won't get overdue

yuwenmemon commented 2 weeks ago

@SzymczakJ sounds like he'll be working on it tomorrow so no need to put a HOLD IMO.

SzymczakJ commented 2 weeks ago

Update: Started working on this, PR draft should be around in one/two days.

SzymczakJ commented 2 weeks ago

Update: still working on draft PR. By the way how is backend for this task looking? If I call Connections.updatePolicyConnectionConfig(just like we did for Xero or QBO) with proper arguments will it work out of the box or do I need to wait for BE to implement it?

isabelastisser commented 2 weeks ago

@yuwenmemon @hungvu193 can you please follow up on the question above? Thanks!

hungvu193 commented 1 week ago

I think it should be similar with QBO and Xero. Let's wait for confirmation from Yuwen

yuwenmemon commented 1 week ago

@SzymczakJ As mentioned in the Design Doc we'll actually be adding individual API commands for each setting, which will require separate action method in the front-end.

They're described in detail in the doc I linked above. As for when they'll be available on production I believe @NikkiWines is actively working on the issue right now so I expect we start seeing them next week.

In the meantime let's build out the actions and use the descriptions of the APIs in the Design Doc so that it's plug-and-play when the APIs go live.

SzymczakJ commented 1 week ago

Still working on it

melvin-bot[bot] commented 1 week ago

@yuwenmemon, @hungvu193, @isabelastisser, @SzymczakJ Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

hungvu193 commented 1 week ago

Still In progress

hungvu193 commented 1 week ago

Same

SzymczakJ commented 6 days ago

I should be able to take this PR out of draft on Monday.

hungvu193 commented 3 days ago

PR will be ready for review today.

SzymczakJ commented 3 days ago

I got a review from @war-in, let me fix his comments and tomorrow the PR will be ready for your review @hungvu193 😄

SzymczakJ commented 2 days ago

PR ready for review. When testing keep in mind that some functionalities don't work and wait to be fixed on BE side:

SzymczakJ commented 2 days ago

Also ready for design team review. The visual part is presented in test steps of PR.

hungvu193 commented 1 day ago

Thank you. I'll take a look today :🙋‍♂️