Merge remote-tracking branch 'origin/trunk' into performance/merchant-view-coupons

This commit is contained in:
Alex López 2022-04-18 10:33:45 +02:00
commit 027ba298f4
290 changed files with 7152 additions and 4921 deletions

View File

@ -41,9 +41,8 @@ If you have questions about the process to contribute code or want to discuss de
- Make sure to write good and detailed commit messages (see [this post](https://chris.beams.io/posts/git-commit/) for more on this) and follow all the applicable sections of the pull request template.
- Please avoid modifying the changelog directly or updating the .pot files. These will be updated by the WooCommerce team.
If you are contributing code to the (Javascript-driven) WooCommerce Admin project or to Gutenberg blocks, note that these are developed in external packages.
If you are contributing code to the (Javascript-driven) Gutenberg blocks, note that it's developed in an external package.
- [WooCommerce Admin](https://github.com/woocommerce/woocommerce-admin)
- [Blocks](https://github.com/woocommerce/woocommerce-gutenberg-products-block)
## Feature Requests 🚀

View File

@ -25,13 +25,10 @@ Closes # .
* [ ] Have you added an explanation of what your changes do and why you'd like us to include them?
* [ ] Have you written new tests for your changes, as applicable?
* [ ] Have you successfully run tests with your changes locally?
* [ ] Have you created a changelog file by running `pnpm nx affected --target=changelog`?
<!-- Mark completed items with an [x] -->
### Changelog entry
> Enter a summary of all changes on this Pull Request. This will appear in the changelog if accepted.
### FOR PR REVIEWER ONLY:
* [ ] I have reviewed that everything is sanitized/escaped appropriately for any SQL or XSS injection possibilities. I made sure Linting is not ignored or disabled.

View File

@ -69,7 +69,7 @@ jobs:
- name: Build Admin feature config
working-directory: ./
run: pnpm nx build:feature-config woocommerce-admin
run: pnpm nx build:feature-config woocommerce
- name: Add PHP8 Compatibility.
run: |

View File

@ -61,7 +61,7 @@ jobs:
- name: Build Admin feature config
working-directory: ./
run: |
pnpm nx build:feature-config woocommerce-admin
pnpm nx build:feature-config woocommerce
- name: Init DB and WP
run: pnpm nx install-unit-test-db woocommerce

26
.github/workflows/pr-lint-monorepo.yml vendored Normal file
View File

@ -0,0 +1,26 @@
name: Run lint checks potentially affecting projects across the monorepo
on: pull_request
concurrency:
group: changelogger-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: true
jobs:
changelogger_used:
name: Changelogger use
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
- name: Check change files are touched for touched projects
env:
BASE: ${{ github.event.pull_request.base.sha }}
HEAD: ${{ github.event.pull_request.head.sha }}
run: php tools/monorepo/check-changelogger-use.php --debug "$BASE" "$HEAD"

View File

@ -69,7 +69,7 @@ jobs:
- name: Build Admin feature config
working-directory: ./
run: |
pnpm nx build:feature-config woocommerce-admin
pnpm nx build:feature-config woocommerce
- name: Add PHP8 Compatibility.
run: |

View File

@ -57,7 +57,6 @@ echo "The pull request was merged by: $merger_user_name\n";
$comment_body = "Hi @$merger_user_name, thanks for merging this pull request. Please take a look at these follow-up tasks you may need to perform:
- [ ] Add the `release: add changelog` label
- [ ] Add the `release: add testing instructions` label";
$add_comment_mutation = "

5
.husky/post-merge Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
pnpm install
pnpm nx affected --target="composer-install" --base=ORIG_HEAD --head=HEAD

View File

@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
node bin/pre-push-hook.js
./bin/pre-push.sh

24
bin/pre-push.sh Executable file
View File

@ -0,0 +1,24 @@
#!/bin/sh
PROTECTED_BRANCH="trunk"
CURRENT_BRANCH=$(git branch --show-current)
if [ $PROTECTED_BRANCH = $CURRENT_BRANCH ]; then
if [ "$TERM" = "dumb" ]; then
>&2 echo "Sorry, you are unable to push to $PROTECTED_BRANCH using a GUI client! Please use git CLI."
exit 1
fi
printf "%sYou're about to push to $PROTECTED_BRANCH, is that what you intended? [y/N]: %s" "$(tput setaf 3)" "$(tput sgr0)"
read -r PROCEED < /dev/tty
echo
if [ "$(echo "${PROCEED:-n}" | tr "[:upper:]" "[:lower:]")" = "y" ]; then
echo "$(tput setaf 2)Brace yourself! Pushing to the $PROTECTED_BRANCH branch...$(tput sgr0)"
echo
exit 0
fi
echo "$(tput setaf 2)Push to $PROTECTED_BRANCH cancelled!$(tput sgr0)"
echo
exit 1
fi

View File

@ -1,5 +1,103 @@
== Changelog ==
= 6.4.0 2022-04-12 =
**WooCommerce**
- Add - Scaffolding for the custom orders table feature. ([#31692](https://github.com/woocommerce/woocommerce/pull/31692))
- Add - Add DB table structure for custom order tables. ([#31811](https://github.com/woocommerce/woocommerce/pull/31811))
- Add - Primary key for the product attributes lookup table. ([#32067](https://github.com/woocommerce/woocommerce/pull/32067))
- Add - Tracks to the dashboard status widget and setup widget. ([#31857](https://github.com/woocommerce/woocommerce/pull/31857))
- Add - Check around setup widget display when features are disabled. ([#31884](https://github.com/woocommerce/woocommerce/pull/31884))
- Add - 'woocommerce_get_formatted_meta_data_include_all_meta_lines' filter hook. This can be used to control whether metadata lines are shown in the order meta box. ([#30948](https://github.com/woocommerce/woocommerce/pull/30948))
- Enhancement - Introduce rate_limit_remaining column in the wc_rate_limits table. ([#32041](https://github.com/woocommerce/woocommerce/pull/32041))
- Tweak - Update PayPal Standard JS used in the admin environment to avoid deprecated functionality. ([#32076](https://github.com/woocommerce/woocommerce/pull/32076))
- Tweak - Change level of escaping used to render the CSV import error log. ([#32000](https://github.com/woocommerce/woocommerce/pull/32000))
- Tweak - Make the payment_url field available via the REST API's orders endpoint. ([#31826](https://github.com/woocommerce/woocommerce/pull/31826))
- Tweak - Rename WC_API_Exception code woocommerce_api_cannot_edit_product_catgory into woocommerce_api_cannot_edit_product_category ([#31785](https://github.com/woocommerce/woocommerce/pull/31785))
- Tweak - Updated default email color to new Woo purple ([#30586](https://github.com/woocommerce/woocommerce/pull/30586))
- Fix - Avoid depending on the presence of a theme header template to clear the cart after payment is made. ([#31877](https://github.com/woocommerce/woocommerce/pull/31877))
- Fix - Payments tab tracking. ([#31844](https://github.com/woocommerce/woocommerce/pull/31844))
- Fix - Remove unnecessary duplicate style in email-styles template. ([#31860](https://github.com/woocommerce/woocommerce/pull/31860))
- Fix - incorrect position value for registering menu pages. ([#31779](https://github.com/woocommerce/woocommerce/pull/31779))
- Fix - SZL currency symbol. Updated from 'L' to 'E'. ([#30602](https://github.com/woocommerce/woocommerce/pull/30602))
- Fix - Removed execution of at least one hook ignoring the `woocommerce_load_webhooks_limit` filter value. ([#29002](https://github.com/woocommerce/woocommerce/pull/29002))
- Dev - Added has_options() to REST API v3 product endpoint response. ([#32031](https://github.com/woocommerce/woocommerce/pull/32031))
- Dev - Added woocommerce_admin_order_should_render_refunds hook to allow control over the refunds UI within the order editor. ([#31414](https://github.com/woocommerce/woocommerce/pull/31414))
**WooCommerce Admin - 3.3.0 & 3.3.1 & 3.3.2**
- Add - Add asynchronous plugin install and activation endpoints ([#8079](https://github.com/woocommerce/woocommerce-admin/pull/8079))
- Performance - Avoid expensive get_notes() queries in CouponPageMoved admin_init actions by using new Notes::get_note_by_name() helper method. ([#8202](https://github.com/woocommerce/woocommerce-admin/pull/8202))
- Enhancement - Add chart color filter for overriding default chart colors. ([#8258](https://github.com/woocommerce/woocommerce-admin/pull/8258))
- Enhancement - Added Typescript type declarations to build for @woocommerce/components ([#8282](https://github.com/woocommerce/woocommerce-admin/pull/8282))
- Enhancement - Increase color selection limit to ten and add additional colors. ([#8258](https://github.com/woocommerce/woocommerce-admin/pull/8258))
- Enhancement - Made @woocommerce/components/Stepper a Typescript file ([#8286](https://github.com/woocommerce/woocommerce-admin/pull/8286))
- Enhancement - Prompts a modal to save any unsaved changes when the users try to move to a different step ([#8278](https://github.com/woocommerce/woocommerce-admin/pull/8278))
- Tweak - OBW: Override Country/Region label line-height style to avoid truncated descenders. ([#8186](https://github.com/woocommerce/woocommerce-admin/pull/8186))
- Tweak - Show single success message for theme install and activation ([#8236](https://github.com/woocommerce/woocommerce-admin/pull/8236))
- Tweak - Use WC_VERSION as cache buster for assets ([#8308](https://github.com/woocommerce/woocommerce-admin/pull/8308))
- Update - Adjust time range and add an image for the Jetpack Backup note. ([#8293](https://github.com/woocommerce/woocommerce-admin/pull/8293))
- Update - Implement MailChimp API request threshold for MailchimpScheduler. ([#8342](https://github.com/woocommerce/woocommerce-admin/pull/8342))
- Update - Reintroduce CES on product add, product update, and order update. ([#8238](https://github.com/woocommerce/woocommerce-admin/pull/8238))
- Update - Replace mysql image with mariadb ([#8220](https://github.com/woocommerce/woocommerce-admin/pull/8220))
- Update - Update country support list for WooCommerce Payments Task. ([#8517](https://github.com/woocommerce/woocommerce-admin/pull/8517))
- Fix - Fix handling of paid themes in purchase task. ([#8493](https://github.com/woocommerce/woocommerce-admin/pull/8493))
- Fix - Make sure the paid extension task is also shown for themes. ([#8412](https://github.com/woocommerce/woocommerce-admin/pull/8412))
- Fix - Reintroduce emphasis on inbox note action button. ([#8411](https://github.com/woocommerce/woocommerce-admin/pull/8411))
- Fix - Remove class ExtendedPayments. ([#8461](https://github.com/woocommerce/woocommerce-admin/pull/8461))
- Fix - Added random IDs to SVG checkmarks in stepper component ([#8222](https://github.com/woocommerce/woocommerce-admin/pull/8222))
- Fix - Fix Google Listings plugin is always shown in free features despite already activated. ([#8330](https://github.com/woocommerce/woocommerce-admin/pull/8330))
- Fix - Fix hidden notes in `admin/notes` endpoint when the user is not in the tasklist experiment. ([#8328](https://github.com/woocommerce/woocommerce-admin/pull/8328))
- Fix - Fix missing product name in variation analytic page for the deleted products. ([#8255](https://github.com/woocommerce/woocommerce-admin/pull/8255))
- Fix - Fix payments extensions displayed below the offline payments options. ([#8232](https://github.com/woocommerce/woocommerce-admin/pull/8232))
- Fix - Fix setup wizard title and flash of content ([#8201](https://github.com/woocommerce/woocommerce-admin/pull/8201))
- Fix - Fix too many pending run_remote_notifications actions. ([#8285](https://github.com/woocommerce/woocommerce-admin/pull/8285))
- Fix - Fix view logic for Setup additional payment providers task. ([#8391](https://github.com/woocommerce/woocommerce-admin/pull/8391))
- Fix - OBW: fix copy on Business Details when "WooCommerce Shipping" is not listed ([#8324](https://github.com/woocommerce/woocommerce-admin/pull/8324))
- Fix - Only add product data on REST requests and task list ([#8235](https://github.com/woocommerce/woocommerce-admin/pull/8235))
- Fix - Stop showing actioned inbox items ([#8394](https://github.com/woocommerce/woocommerce-admin/pull/8394))
- Fix - WC Payments task is not visible after installing the plugin ([#8514](https://github.com/woocommerce/woocommerce-admin/pull/8514))
- Fix - PHP warning when default param is missing in payments spec. ([#8519](https://github.com/woocommerce/woocommerce-admin/pull/8519))
- Dev - Added a test for tracks event recording for PaymentGatewaySuggestions ([#8306](https://github.com/woocommerce/woocommerce-admin/pull/8306))
- Dev - Add README to hook reference generation script ([#8004](https://github.com/woocommerce/woocommerce-admin/pull/8004))
- Dev - Add reset WooCommerce functionality to E2E tests, so tests have a fresh state. ([#8219](https://github.com/woocommerce/woocommerce-admin/pull/8219))
- Dev - Enabled optional typescript checking on ./client subfolder ([#8372](https://github.com/woocommerce/woocommerce-admin/pull/8372))
- Dev - Fix formatting and add filter param for changelog types for the testing instructions script. ([#8256](https://github.com/woocommerce/woocommerce-admin/pull/8256))
- Dev - Refactor MerchantEmailNotifications ([#8304](https://github.com/woocommerce/woocommerce-admin/pull/8304))
- Dev - Remove preloaded countries from data endpoints and use data store instead. ([#8380](https://github.com/woocommerce/woocommerce-admin/pull/8380))
- Dev - Remove unused pre loaded setting data displaying all the routes. ([#8379](https://github.com/woocommerce/woocommerce-admin/pull/8379))
- Dev - Remove unused task styling classes ([#8234](https://github.com/woocommerce/woocommerce-admin/pull/8234))
- Dev - Update dependencies to support react 17 and drop support for IE11. ([#8305](https://github.com/woocommerce/woocommerce-admin/pull/8305))
- Dev - Update task list data structure to better handle new designs. ([#8332](https://github.com/woocommerce/woocommerce-admin/pull/8332))
**WooCommerce Blocks - 7.2.0 & 7.2.1**
- Enhancement - Add Global Styles support to the Product Price block. ([5950](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5950))
- Enhancement - Add Global Styles support to the Add To Cart Button block. ([5816](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5816))
- Enhancement - Store API - Introduced `wc/store/v1` namespace. ([5911](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5911))
- Enhancement - Renamed WooCommerce block templates to more e-commerce related names. ([5935](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5935))
- Enhancement - Featured Product block: Add the ability to reset to a previously set custom background image. ([5886](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5886))
- Enhancement - Add a remove image button to the WooCommerce Feature Category block. ([5719](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5719))
- Enhancement - Add support for the global style for the On-Sale Badge block. ([5565](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5565))
- Enhancement - Add support for the global style for the Attribute Filter block. ([5557](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5557))
- Enhancement - Category List block: Add support for global style. ([5516](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5516))
- Fix - Fixed typo in `wooocommerce_store_api_validate_add_to_cart` and `wooocommerce_store_api_validate_cart_item` hook names. ([5926](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5926))
- Fix - Fix loading WC core translations in locales where WC Blocks is not localized for some strings. ([5910](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5910))
- Fix - Fixed an issue where clear customizations functionality was not working for WooCommerce templates. ([5746](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5746))
- Fix - Fixed hover and focus states for button components. ([5712](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5712))
- Fix - Add to Cart button on Products listing blocks will respect the "Redirect to the cart page after successful addition" setting. ([5708](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5708))
- Fix - Fixes Twenty Twenty Two issues with sales price and added to cart "View Cart" call out styling in the "Products by Category" block. ([5684](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5684))
- Fix - StoreAPI: Clear all wc notice types in the cart validation context [#5983](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5983)
- Fix - Don't trigger class deprecations notices if headers are already sent [#6074](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/6074)
- Various - Remove v1 string from Store Keys. ([5987](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5987))
- Various - Introduce the `InvalidCartException` for handling cart validation. ([5904](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5904))
- Various - Renamed Store API custom headers to remove `X-WC-Store-API` prefixes. [#5983](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5983)
- Various - Normalised Store API error codes [#5992](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5992)
- Various - Deprecated `woocommerce_blocks_checkout_order_processed` in favour of `woocommerce_store_api_checkout_order_processed`
- Various - Deprecated `woocommerce_blocks_checkout_update_order_meta` in favour of `woocommerce_store_api_checkout_update_order_meta`
- Various - Deprecated `woocommerce_blocks_checkout_update_order_from_request` in favour of `woocommerce_store_api_checkout_update_order_from_request`
= 6.3.1 2022-03-10 =
**WooCommerce**

View File

@ -14,7 +14,9 @@
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"scripts": {
"preinstall": "npx only-allow pnpm"
"preinstall": "npx only-allow pnpm",
"postinstall": "pnpm git:update-hooks",
"git:update-hooks": "rm -r .git/hooks && mkdir -p .git/hooks && husky install"
},
"devDependencies": {
"@automattic/nx-composer": "^0.1.0",
@ -30,7 +32,9 @@
"@wordpress/prettier-config": "^1.1.1",
"chalk": "^4.1.2",
"glob": "^7.2.0",
"husky": "^7.0.4",
"jest": "^27.3.1",
"lint-staged": "^12.3.7",
"mkdirp": "^1.0.4",
"node-stream-zip": "^1.15.0",
"prettier": "npm:wp-prettier@^2.2.1-beta-1",

View File

@ -36,13 +36,13 @@ To create a new package, add a new folder to `/packages`, containing…
"author": "Automattic",
"license": "GPL-2.0-or-later",
"keywords": [ "wordpress", "woocommerce" ],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/[_YOUR_PACKAGE_]/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/main/packages/[_YOUR_PACKAGE_]/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -1,5 +1,11 @@
# Unreleased
- Add E2E tests to disabled welcome modal #32505
- Update test for payment task. #32467
- Increase timeout threshold for payment task. #32605
# 1.0.0
- Add returned type annotations and remove unused vars. #8020

View File

@ -3,10 +3,10 @@
"version": "1.0.0",
"author": "Automattic",
"description": "E2E tests for the new WooCommerce interface.",
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/admin-e2e-tests/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/admin-e2e-tests/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"keywords": [
"woocommerce",
@ -56,5 +56,10 @@
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"lint": "eslint src",
"prepack": "pnpm run clean && pnpm run build"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -21,8 +21,20 @@ export class PaymentsSetup extends BasePage {
await waitForElementByText( 'h1', 'Set up payments' );
}
async closeHelpModal(): Promise< void > {
await this.clickButtonWithText( 'Got it' );
async possiblyCloseHelpModal(): Promise< void > {
try {
await this.clickButtonWithText( 'Got it' );
} catch ( e ) {}
}
async showOtherPaymentMethods(): Promise< void > {
const selector = '.woocommerce-task-payments button.toggle-button';
await this.page.waitForSelector( selector );
const toggleButton = await this.page.$(
`${ selector }[aria-expanded=false]`
);
await toggleButton?.click();
await waitForElementByText( 'h2', 'Offline payment methods' );
}
async goToPaymentMethodSetup(
@ -41,14 +53,6 @@ export class PaymentsSetup extends BasePage {
}
}
async methodHasBeenSetup( method: PaymentMethod ): Promise< void > {
const selector = `.woocommerce-task-payment-${ method }`;
await this.page.waitForSelector( selector );
expect(
await getElementByText( '*', 'Manage', selector )
).toBeDefined();
}
async enableCashOnDelivery(): Promise< void > {
await this.page.waitForSelector( '.woocommerce-task-payment-cod' );
await this.clickButtonWithText( 'Enable' );

View File

@ -24,12 +24,7 @@ export class WcHomescreen extends BasePage {
}
async possiblyDismissWelcomeModal(): Promise< void > {
const modalText = 'Welcome to your WooCommerce stores online HQ!';
const modal = await waitForElementByTextWithoutThrow(
'h2',
modalText,
10
);
const modal = await this.isWelcomeModalVisible();
if ( modal ) {
await this.clickButtonWithText( 'Next' );
@ -41,6 +36,16 @@ export class WcHomescreen extends BasePage {
}
}
async isWelcomeModalVisible(): Promise< boolean > {
const modalText = 'Welcome to your WooCommerce stores online HQ!';
const modal = await waitForElementByTextWithoutThrow(
'h2',
modalText,
10
);
return modal;
}
async getTaskList(): Promise< Array< string | null > > {
await page.waitForSelector(
'.woocommerce-task-card .woocommerce-task-list__item-title'

View File

@ -42,8 +42,22 @@ export class WcSettings extends BasePage {
);
}
async paymentMethodIsEnabled( method = '' ): Promise< boolean > {
await this.navigate( 'checkout' );
await waitForElementByText( 'h2', 'Payment methods' );
const className = await getAttribute(
`tr[data-gateway_id=${ method }] .woocommerce-input-toggle`,
'className'
);
return (
( className as string ).indexOf(
'woocommerce-input-toggle--disabled'
) === -1
);
}
async cleanPaymentMethods(): Promise< void > {
this.navigate( 'checkout' );
await this.navigate( 'checkout' );
await waitForElementByText( 'h2', 'Payment methods' );
const paymentMethods = await page.$$( 'span.woocommerce-input-toggle' );
for ( const method of paymentMethods ) {

View File

@ -597,10 +597,37 @@ const testBusinessDetailsForm = () => {
} );
};
const testAdminHomescreen = () => {
describe( 'Homescreen', () => {
const profileWizard = new OnboardingWizard( page );
const homeScreen = new WcHomescreen( page );
const login = new Login( page );
beforeAll( async () => {
await login.login();
await resetWooCommerceState();
await profileWizard.navigate();
await profileWizard.skipStoreSetup();
} );
afterAll( async () => {
await login.logout();
} );
it( 'should not show welcome modal', async () => {
await homeScreen.isDisplayed();
await expect( homeScreen.isWelcomeModalVisible() ).resolves.toBe(
false
);
} );
} );
};
module.exports = {
testAdminOnboardingWizard,
testSelectiveBundleWCPay,
testDifferentStoreCurrenciesWCPay,
testSubscriptionsInclusion,
testBusinessDetailsForm,
testAdminHomescreen,
};

View File

@ -48,11 +48,13 @@ const testAdminPaymentSetupTask = () => {
it( 'Can visit the payment setup task from the homescreen if the setup wizard has been skipped', async () => {
await homeScreen.clickOnTaskList( 'Set up payments' );
await paymentsSetup.closeHelpModal();
await paymentsSetup.possiblyCloseHelpModal();
await paymentsSetup.isDisplayed();
} );
it( 'Saving valid bank account transfer details enables the payment method', async () => {
it.skip( 'Saving valid bank account transfer details enables the payment method', async () => {
await paymentsSetup.showOtherPaymentMethods();
await waitForTimeout( 500 );
await paymentsSetup.goToPaymentMethodSetup( 'bacs' );
await bankTransferSetup.saveAccountDetails( {
accountNumber: '1234',
@ -62,27 +64,28 @@ const testAdminPaymentSetupTask = () => {
iban: '12 3456 7890',
swiftCode: 'ABBA',
} );
await homeScreen.isDisplayed();
await waitForTimeout( 1000 );
await homeScreen.clickOnTaskList( 'Set up payments' );
await paymentsSetup.isDisplayed();
await paymentsSetup.methodHasBeenSetup( 'bacs' );
await waitForTimeout( 1500 );
expect( await settings.paymentMethodIsEnabled( 'bacs' ) ).toBe(
true
);
await homeScreen.navigate();
} );
it( 'Enabling cash on delivery enables the payment method', async () => {
it.skip( 'Enabling cash on delivery enables the payment method', async () => {
await settings.cleanPaymentMethods();
await homeScreen.navigate();
await homeScreen.isDisplayed();
await waitForTimeout( 1000 );
await homeScreen.clickOnTaskList( 'Set up payments' );
await paymentsSetup.enableCashOnDelivery();
await homeScreen.navigate();
await homeScreen.isDisplayed();
await waitForTimeout( 1000 );
await homeScreen.clickOnTaskList( 'Set up payments' );
await paymentsSetup.possiblyCloseHelpModal();
await paymentsSetup.isDisplayed();
await paymentsSetup.methodHasBeenSetup( 'cod' );
await paymentsSetup.showOtherPaymentMethods();
await waitForTimeout( 500 );
await paymentsSetup.enableCashOnDelivery();
await waitForTimeout( 1500 );
expect( await settings.paymentMethodIsEnabled( 'cod' ) ).toBe(
true
);
} );
} );
};

View File

@ -33,5 +33,10 @@
},
"bin": {
"wc-api-tests": "bin/wc-api-tests.sh"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -52,5 +52,10 @@
},
"publishConfig": {
"access": "public"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -1,5 +1,10 @@
# Unreleased
- Fix documentation for `TableCard` component
- Update dependency `@wordpress/hooks` to ^3.5.0
- Update dependency `@wordpress/icons` to ^8.1.0
- Add `className` prop for Pill component. #32605
# 10.0.0
- Replace deprecated wp.compose.withState with wp.element.useState. #8338
- Add missing dependencies. #8349

View File

@ -9,13 +9,13 @@
"woocommerce",
"components"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/components/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/components/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -39,10 +39,10 @@
"@wordpress/deprecated": "^3.3.1",
"@wordpress/dom": "^3.3.2",
"@wordpress/element": "^4.1.1",
"@wordpress/hooks": "^2.12.3",
"@wordpress/hooks": "^3.5.0",
"@wordpress/html-entities": "^3.3.1",
"@wordpress/i18n": "^4.3.1",
"@wordpress/icons": "^6.3.0",
"@wordpress/icons": "^8.1.0",
"@wordpress/keycodes": "^3.3.1",
"@wordpress/url": "^3.4.1",
"@wordpress/viewport": "^4.1.2",
@ -123,5 +123,11 @@
"test:nobuild": "jest --config ./jest.config.json",
"test:update-snapshots": "pnpm run test:nobuild -- --updateSnapshot",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix",
"pnpm test-staged"
]
}
}

View File

@ -124,7 +124,7 @@ const config = {
};
```
`type`: A string Autocompleter type used by the [Search Component](https://github.com/woocommerce/woocommerce-admin/tree/main/packages/components/src/search).
`type`: A string Autocompleter type used by the [Search Component](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/components/src/search).
`getLabels`: A function returning a Promise resolving to an array of objects with `id` and `label` properties.
### Date

View File

@ -2,16 +2,17 @@
* External dependencies
*/
import { createElement } from '@wordpress/element';
import classnames from 'classnames';
/**
* Internal dependencies
*/
import { Text } from '../experimental';
export function Pill( { children } ) {
export function Pill( { children, className } ) {
return (
<Text
className="woocommerce-pill"
className={ classnames( 'woocommerce-pill', className ) }
variant="caption"
as="span"
size="12"

View File

@ -67,8 +67,8 @@ Name | Type | Default | Description
`downloadable` | Boolean | `false` | Whether the table must be downloadable. If true, the download button will appear
`onClickDownload` | Function | `null` | A callback function called when the "download" button is pressed. Optional, if used, the download button will appear
`query` | Object | `{}` | An object of the query parameters passed to the page, ex `{ page: 2, per_page: 5 }`
`rowHeader` | One of type: number, bool | `0` | An array of arrays of display/value object pairs (see `Table` props)
`rows` | Array | `[]` | Which column should be the row header, defaults to the first item (`0`) (see `Table` props)
`rowHeader` | One of type: number, bool | `0` | Which column should be the row header, defaults to the first item (`0`) (see `Table` props)
`rows` | Array | `[]` | (required) An array of arrays of display/value object pairs (see `Table` props)
`rowsPerPage` | Number | `null` | (required) The total number of rows to display per page
`searchBy` | String | `null` | The string to use as a query parameter when searching row items
`showMenu` | Boolean | `true` | Boolean to determine whether or not ellipsis menu is shown

View File

@ -308,11 +308,12 @@ TableCard.propTypes = {
*/
query: PropTypes.object,
/**
* An array of arrays of display/value object pairs (see `Table` props).
* Which column should be the row header, defaults to the first item (`0`) (but could be set to `1`, if the first col
* is checkboxes, for example). Set to false to disable row headers.
*/
rowHeader: PropTypes.oneOfType( [ PropTypes.number, PropTypes.bool ] ),
/**
* Which column should be the row header, defaults to the first item (`0`) (see `Table` props).
* An array of arrays of display/value object pairs (see `Table` props).
*/
rows: PropTypes.arrayOf(
PropTypes.arrayOf(

View File

@ -9,13 +9,13 @@
"woocommerce",
"csv"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/csv-export/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/csv-export/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -46,5 +46,11 @@
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"typescript": "^4.6.2"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix",
"pnpm test-staged"
]
}
}

View File

@ -9,13 +9,13 @@
"woocommerce",
"currency"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/currency/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/currency/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -49,5 +49,11 @@
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"typescript": "^4.6.2"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix",
"pnpm test-staged"
]
}
}

View File

@ -8,13 +8,13 @@
"wordpress",
"woocommerce"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/customer-effort-score/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/customer-effort-score/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -70,5 +70,11 @@
"test": "pnpm run build && pnpm run test:nobuild",
"test:nobuild": "jest --config ./jest.config.json",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix",
"pnpm test-staged"
]
}
}

View File

@ -1,5 +1,8 @@
# Unreleased
- Update dependency `@wordpress/hooks` to ^3.5.0
- Add `is_offline` attribute for `Plugin` type. #32467
# 3.1.0
- Add "moment" to peerDependencies. #8349

View File

@ -9,13 +9,13 @@
"woocommerce",
"data"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/data/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/data/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -30,7 +30,7 @@
"@wordpress/data-controls": "^2.3.2",
"@wordpress/deprecated": "^3.3.1",
"@wordpress/element": "^4.1.1",
"@wordpress/hooks": "^2.12.3",
"@wordpress/hooks": "^3.5.0",
"@wordpress/i18n": "^4.3.1",
"@wordpress/url": "^3.4.1",
"dompurify": "^2.3.6",
@ -70,5 +70,11 @@
"test": "pnpm run build && pnpm run test:nobuild",
"test:nobuild": "jest --config ./jest.config.json",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix",
"pnpm test-staged"
]
}
}

View File

@ -34,6 +34,7 @@ export { withPluginsHydration } from './plugins/with-plugins-hydration';
export { ONBOARDING_STORE_NAME } from './onboarding';
export { withOnboardingHydration } from './onboarding/with-onboarding-hydration';
export { getVisibleTasks } from './onboarding/utils';
export type { TaskType, TaskListType } from './onboarding/types';
export { USER_STORE_NAME } from './user';

View File

@ -9,12 +9,22 @@ export type TaskType = {
isSnoozed: boolean;
isVisible: boolean;
isSnoozable: boolean;
isDisabled: boolean;
snoozedUntil: number;
time: string;
title: string;
isVisited: boolean;
};
export type TaskListSection = {
id: string;
title: string;
description: string;
image: string;
tasks: string[];
isComplete: boolean;
};
export type TaskListType = {
id: string;
isCollapsible?: boolean;
@ -25,4 +35,5 @@ export type TaskListType = {
title: string;
eventPrefix: string;
displayProgressHeader: boolean;
sections?: TaskListSection[];
};

View File

@ -0,0 +1,16 @@
/**
* Internal dependencies
*/
import { TaskType } from './types';
/**
* Filters tasks to only visible tasks, taking in account snoozed tasks.
*/
export function getVisibleTasks( tasks: TaskType[] ) {
const nowTimestamp = Date.now();
return tasks.filter(
( task ) =>
! task.isDismissed &&
( ! task.isSnoozed || task.snoozedUntil < nowTimestamp )
);
}

View File

@ -55,4 +55,8 @@ export const pluginNames = {
'google-listings-and-ads': __( 'Google Listings and Ads', 'woocommerce' ),
'woo-razorpay': __( 'Razorpay', 'woocommerce' ),
mailpoet: __( 'MailPoet', 'woocommerce' ),
'pinterest-for-woocommerce': __(
'Pinterest for WooCommerce',
'woocommerce'
),
};

View File

@ -39,6 +39,7 @@ export type Plugin = {
recommendation_priority?: number;
is_visible?: boolean;
is_local_partner?: boolean;
is_offline?: boolean;
};
type PaypalOnboardingState = 'unknown' | 'start' | 'progressive' | 'onboarded';

View File

@ -9,13 +9,13 @@
"woocommerce",
"date"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/date/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/date/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -52,5 +52,11 @@
"test": "pnpm run build && pnpm run test:nobuild",
"test:nobuild": "jest --config ./jest.config.json",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix",
"pnpm test-staged"
]
}
}

View File

@ -8,13 +8,13 @@
"wordpress",
"woocommerce"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/dependency-extraction-webpack-plugin/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/dependency-extraction-webpack-plugin/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "src/index.js",
"dependencies": {
@ -34,5 +34,10 @@
"typescript": "^4.6.2",
"webpack": "^5.70.0",
"webpack-cli": "^3.3.12"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -48,5 +48,10 @@
"clean": "rm -rf ./build ./build-module",
"compile": "node ./../bin/build.js",
"build": "./bin/build.sh && pnpm run clean && pnpm run compile"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -77,5 +77,10 @@
},
"bin": {
"wc-e2e": "bin/wc-e2e.sh"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -45,5 +45,10 @@
"build": "pnpm run clean && pnpm run compile",
"prepare": "pnpm run build",
"lint": "eslint src"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -10,14 +10,14 @@
"eslint",
"plugin"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/eslint-plugin/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/eslint-plugin/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git",
"url": "https://github.com/woocommerce/woocommerce.git",
"directory": "packages/eslint-plugin"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"files": [
"configs",

View File

@ -1,5 +1,7 @@
# Unreleased
- Update dependency `@wordpress/icons` to ^8.1.0
# 3.0.1
- Update all js packages with minor/patch version changes. #8392

View File

@ -9,13 +9,13 @@
"woocommerce",
"experimental"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/experimental/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/experimental/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -29,7 +29,7 @@
"@wordpress/components": "^19.5.0",
"@wordpress/element": "^4.1.1",
"@wordpress/i18n": "^4.3.1",
"@wordpress/icons": "^6.3.0",
"@wordpress/icons": "^8.1.0",
"@wordpress/keycodes": "^3.3.1",
"classnames": "^2.3.1",
"dompurify": "^2.3.6",
@ -83,5 +83,11 @@
"test": "pnpm run build && pnpm run test:nobuild",
"test:nobuild": "jest --config ./jest.config.json",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix",
"pnpm test-staged"
]
}
}

View File

@ -130,7 +130,7 @@ export const TaskItem: React.FC< TaskItemProps > = ( {
}, [ expanded ] );
const className = classnames( 'woocommerce-task-list__item', {
complete: completed,
'is-complete': completed,
expanded: isTaskExpanded,
'level-2': level === 2 && ! completed,
'level-1': level === 1 && ! completed,

View File

@ -121,7 +121,7 @@ $task-alert-yellow: #f0b849;
left: 5px;
}
&.complete {
&.is-complete {
.woocommerce-task__icon {
background-color: var(--wp-admin-theme-color);
}
@ -136,7 +136,7 @@ $task-alert-yellow: #f0b849;
}
}
&:not(.complete) {
&:not(.is-complete) {
.woocommerce-task__icon {
border: 1px solid $gray-100;
background: $white;

View File

@ -1,5 +1,7 @@
# Unreleased
- Update dependency `@wordpress/hooks` to ^3.5.0
# 2.1.0
- Add missing dependencies. #8349

View File

@ -10,13 +10,13 @@
"abtest",
"explat"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/explat/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/explat/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -28,7 +28,7 @@
"@automattic/explat-client": "^0.0.3",
"@automattic/explat-client-react-helpers": "^0.0.4",
"@wordpress/api-fetch": "^6.0.1",
"@wordpress/hooks": "^2.12.3",
"@wordpress/hooks": "^3.5.0",
"cookie": "^0.4.2",
"qs": "^6.10.3"
},
@ -54,5 +54,11 @@
"test": "pnpm run build && pnpm run test:nobuild",
"test:nobuild": "jest --config ./jest.config.json",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix",
"pnpm test-staged"
]
}
}

View File

@ -4,14 +4,14 @@
"description": "JavaScript test tooling.",
"author": "Automattic",
"license": "GPL-2.0-or-later",
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/js-tests/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/js-tests/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git",
"url": "https://github.com/woocommerce/woocommerce.git",
"directory": "packages/js-tests"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"private": true,
"main": "build/util/index.js",
@ -40,5 +40,10 @@
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"typescript": "^4.6.2"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -107,7 +107,7 @@ wooCommercePackages.forEach( ( lib ) => {
} );
} );
const config = require( '../../../../plugins/woocommerce-admin/config/development.json' );
const config = require( '../../../../plugins/woocommerce/client/admin/config/development.json' );
// Check if test is jsdom or node
if ( global.window ) {

View File

@ -1,5 +1,7 @@
# Unreleased
- Update dependency `@wordpress/hooks` to ^3.5.0
# 7.0.1
- Add missing dependencies. #8349

View File

@ -9,13 +9,13 @@
"woocommerce",
"navigation"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/navigation/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/navigation/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -25,7 +25,7 @@
"@wordpress/components": "^19.5.0",
"@wordpress/compose": "^5.1.2",
"@wordpress/element": "^4.1.1",
"@wordpress/hooks": "^2.12.3",
"@wordpress/hooks": "^3.5.0",
"@wordpress/notices": "^3.3.2",
"@wordpress/url": "^3.4.1",
"history": "^4.10.1",
@ -57,5 +57,11 @@
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"typescript": "^4.6.2"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix",
"pnpm test-staged"
]
}
}

View File

@ -2,6 +2,8 @@
# Unreleased
- Update dependency `@wordpress/a11y` to ^3.5.0
# 4.0.1
- Update all js packages with minor/patch version changes. #8392

View File

@ -22,7 +22,7 @@
"module": "build-module/index.js",
"react-native": "src/index",
"dependencies": {
"@wordpress/a11y": "^2.15.3",
"@wordpress/a11y": "^3.5.0",
"@wordpress/data": "^6.3.0",
"@wordpress/notices": "^3.3.2"
},
@ -51,5 +51,10 @@
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"typescript": "^4.6.2"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -8,13 +8,13 @@
"wordpress",
"woocommerce"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/number/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/number/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -45,5 +45,11 @@
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"typescript": "^4.6.2"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix",
"pnpm test-staged"
]
}
}

View File

@ -1,5 +1,7 @@
# Unreleased
- Update TaskList types.
# 3.0.1
- Add missing dependency.

View File

@ -9,13 +9,13 @@
"woocommerce",
"onboarding"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/onboarding/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/onboarding/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -59,5 +59,10 @@
"start": "concurrently \"tsc --build --watch\" \"webpack --watch\"",
"prepack": "pnpm run clean && pnpm run build",
"lint": "eslint src"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -8,18 +8,18 @@
"wordpress",
"woocommerce"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/style-build/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/style-build/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "index.js",
"dependencies": {
"@automattic/color-studio": "^2.5.0",
"@wordpress/base-styles": "^3.6.0",
"@wordpress/base-styles": "^4.3.0",
"@wordpress/postcss-plugins-preset": "^1.6.0",
"css-loader": "^3.6.0",
"mini-css-extract-plugin": "^2.6.0",
@ -42,5 +42,10 @@
"ts-jest": "^27.1.3",
"typescript": "^4.6.2",
"webpack": "^5.70.0"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -9,13 +9,13 @@
"woocommerce",
"tracks"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/tracks/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/tracks/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
@ -42,5 +42,10 @@
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"typescript": "^4.6.2"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"eslint --fix"
]
}
}

View File

@ -27,7 +27,7 @@
<!-- Configs -->
<config name="minimum_supported_wp_version" value="5.2" />
<config name="testVersion" value="7.0-" />
<config name="testVersion" value="7.2-" />
<!-- Rules -->
<rule ref="WooCommerce-Core" />
@ -128,4 +128,16 @@
<exclude-pattern>src/Internal/Admin/</exclude-pattern>
<exclude-pattern>src/Admin/</exclude-pattern>
</rule>
<!-- Temporary -->
<rule ref="Squiz.Classes.ClassFileName.NoMatch">
<exclude-pattern>src/Internal/Admin/</exclude-pattern>
<exclude-pattern>src/Admin/</exclude-pattern>
</rule>
<!-- Temporary -->
<rule ref="Squiz.Classes.ValidClassName.NotCamelCaps">
<exclude-pattern>src/Internal/Admin/</exclude-pattern>
<exclude-pattern>src/Admin/</exclude-pattern>
</rule>
</ruleset>

View File

@ -1,57 +0,0 @@
name: 'Daily E2E Tests'
on:
schedule:
- cron: '0 0 * * *'
jobs:
e2e-tests:
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
wordpress: ['https://wordpress.org/latest.zip', 'https://wordpress.org/nightly-builds/wordpress-latest.zip']
woocommerce: ['https://downloads.wordpress.org/plugin/woocommerce.zip', 'https://github.com/woocommerce/woocommerce/releases/download/nightly/woocommerce-trunk-nightly.zip']
exclude:
- {'wordpress': 'https://wordpress.org/nightly-builds/wordpress-latest.zip', 'woocommerce': 'https://github.com/woocommerce/woocommerce/releases/download/nightly/woocommerce-trunk-nightly.zip'}
steps:
- name: Check out repository code
uses: actions/checkout@v2
- name: Install PHP dependencies
run: |
composer install --no-dev
- name: Setup Node.js
uses: actions/setup-node@v2-beta
with:
node-version: '14'
- name: Install PNPM and install dependencies
uses: pnpm/action-setup@v2.2.1
with:
version: ^6.24.2
run_install: true
- name: Build
run: |
composer require wp-cli/i18n-command
pnpm run build:feature-config
pnpm run build
- name: Setup wp-env
env:
WP_ENV_CONFIG: '{ core: "${{ matrix.wordpress }}", plugins: [ ".", "${{ matrix.woocommerce }}" ] }'
run: |
pnpm -g i @wordpress/env
printf '%s\n' "$WP_ENV_CONFIG" > .wp-env-override.json
WP_ENV_TESTS_PORT=8084 wp-env start
wp-env run tests-cli "wp post create --post_type=page --post_status=publish --post_title='Ready' --post_content='E2E-tests.'"
- name: Test
env:
WC_E2E_SCREENSHOTS: 1
run: |
pnpm exec wc-e2e test:e2e
- name: Archive e2e test screenshots
if: ${{ always() }}
uses: actions/upload-artifact@v2
with:
name: e2e-screenshots
path: tests/e2e/screenshots
if-no-files-found: ignore
retention-days: 5

View File

@ -1,40 +0,0 @@
name: 'Daily PHP Tests'
on:
schedule:
- cron: '0 0 * * *'
jobs:
daily-test-php:
name: "Test PHP"
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
wordpress: ['latest', 'nightly']
woocommerce: ['latest', 'nightly']
exclude:
- {'wordpress': 'nightly', 'woocommerce': 'nightly'}
steps:
- name: Check out repository code
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2-beta
with:
node-version: '14'
- name: Install PNPM and install dependencies
uses: pnpm/action-setup@v2.2.1
with:
version: ^6.24.2
run_install: true
- name: Build
run: |
pnpm run build:feature-config
composer install --no-dev
shell: bash
- name: Run the PHP unit tests
env:
WP_VERSION: ${{ matrix.wordpress }}
WC_VERSION: ${{ matrix.woocommerce }}
run: pnpm run test:php
shell: bash

View File

@ -1,50 +0,0 @@
name: E2E tests
on: [pull_request]
jobs:
e2e-tests:
runs-on: ubuntu-18.04
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.7.0
with:
access_token: ${{ github.token }}
- name: Check out repository code
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@2.9.0
with:
php-version: '7.3'
- name: Install PHP dependencies
run: |
composer self-update 2.0.6
composer i
- name: Setup Node.js
uses: actions/setup-node@v2-beta
with:
node-version: '14'
- name: Install PNPM and install dependencies
uses: pnpm/action-setup@v2.2.1
with:
version: ^6.24.2
run_install: true
- name: Build and run E2E Tests
env:
WC_E2E_SCREENSHOTS: 1
E2E_SLACK_CHANNEL: ${{ secrets.E2E_SLACK_CHANNEL }}
E2E_SLACK_TOKEN: ${{ secrets.E2E_SLACK_TOKEN }}
WP_VERSION: '5.8.0'
run: |
composer require wp-cli/i18n-command
pnpm run build
pnpm run e2e:docker-up
sleep 10
pnpm exec wc-e2e test:e2e
- name: Archive e2e test screenshots
if: ${{ always() }}
uses: actions/upload-artifact@v2
with:
name: e2e-screenshots
path: tests/e2e/screenshots
if-no-files-found: ignore
retention-days: 5

View File

@ -1,33 +0,0 @@
name: Publish docs
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2-beta
with:
node-version: '14'
- name: Install PNPM and install dependencies
uses: pnpm/action-setup@v2.2.1
with:
version: ^6.24.2
run_install: true
- name: Build
run: |
pnpm run build
pnpm run docs
- name: Deploy docs
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: gh-pages
publish_dir: ./docs

View File

@ -1,25 +0,0 @@
name: Lint the PHP
on: [pull_request]
jobs:
lint-php:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.7.0
with:
access_token: ${{ github.token }}
- name: Check out repository code
uses: actions/checkout@v2
- name: Determine changed files
id: changed-files
uses: wyrihaximus/github-action-files-in-commit@v1.0
- name: Setup PHP
uses: shivammathur/setup-php@2.9.0
with:
php-version: 7.3
- name: Lint the PHP
env:
CHANGED_FILES: ${{ steps.changed-files.outputs.files }}
run: bin/phpcs.sh
shell: bash

View File

@ -1,87 +0,0 @@
name: Run PHP unit tests
on: [pull_request]
jobs:
test-php:
env:
WP_CORE_DIR: '/tmp/wordpress'
COMPOSER_DEV: 1
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
php: ['7.1', '7.2', '7.3']
wordpress: ['5.4', '5.6']
woocommerce: ['4.8.0', '4.9.1']
phpunit: ['7.5.20']
composer: ['2.0.6']
include:
- php: '7.0'
wordpress: '5.6'
woocommerce: 'latest'
phpunit: '6.5.9'
composer: '1.10.19'
- php: '7.0'
wordpress: '5.6'
woocommerce: '4.9.1'
phpunit: '6.5.9'
composer: '2.0.6'
- php: '8.0'
wordpress: '5.6'
woocommerce: '5.1.0'
phpunit: '7.5.20'
composer: '2.0.6'
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.7.0
with:
access_token: ${{ github.token }}
- name: Check out repository code
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@2.9.0
with:
php-version: ${{matrix.php}}
tools: phpunit:${{matrix.phpunit}}
extensions: mysqli
- name: Setup Node.js
uses: actions/setup-node@v2-beta
with:
node-version: '14'
- name: Install PNPM and install dependencies
uses: pnpm/action-setup@v2.2.1
with:
version: ^6.24.2
run_install: true
- name: Set up the tests
env:
WP_VERSION: ${{matrix.wordpress}}
WC_VERSION: ${{matrix.woocommerce}}
PHP_UNIT: ${{matrix.phpunit}}
COMPOSER_VERSION: ${{matrix.composer}}
run: |
sudo /etc/init.d/mysql start
bash bin/ci/gh-install-wp-tests.sh wc_admin_test root 'root' localhost
cd "$WP_CORE_DIR/wp-content/plugins/woocommerce-admin/"
pnpm run build:feature-config
composer install
node --version
pnpm --version
timedatectl
- name: Add PHP8 Compatibility.
run: |
if [ "$(php -r "echo version_compare(PHP_VERSION,'8.0','>=');")" ]; then
cd "$WP_CORE_DIR/wp-content/plugins/woocommerce-admin/"
composer install
curl -L https://github.com/woocommerce/phpunit/archive/add-compatibility-with-php8-to-phpunit-7.zip -o /tmp/phpunit-7.5-fork.zip
unzip -d /tmp/phpunit-7.5-fork /tmp/phpunit-7.5-fork.zip
composer bin phpunit config --unset platform
composer bin phpunit config repositories.0 '{"type": "path", "url": "/tmp/phpunit-7.5-fork/phpunit-add-compatibility-with-php8-to-phpunit-7", "options": {"symlink": false}}'
composer bin phpunit require --dev -W phpunit/phpunit:@dev --ignore-platform-reqs
rm -rf ./vendor/phpunit/
composer dump-autoload
fi
- name: Run the PHP unit tests
run: bin/phpunit.sh
shell: bash

View File

@ -1,62 +0,0 @@
/* eslint-disable */
module.exports = function( grunt ) {
'use strict';
// Project configuration
grunt.initConfig( {
makepot: {
target: {
options: {
domainPath: '/languages',
exclude: [ '.git/*', 'bin/*', 'node_modules/*', 'tests/*' ],
mainFile: 'woocommerce-admin.php',
potFilename: 'woocommerce-admin.pot',
potHeaders: {
poedit: true,
'x-poedit-keywordslist': true,
},
type: 'wp-plugin',
updateTimestamp: true,
},
},
},
checktextdomain: {
options: {
text_domain: 'woocommerce',
keywords: [
'__:1,2d',
'_e:1,2d',
'_x:1,2c,3d',
'esc_html__:1,2d',
'esc_html_e:1,2d',
'esc_html_x:1,2c,3d',
'esc_attr__:1,2d',
'esc_attr_e:1,2d',
'esc_attr_x:1,2c,3d',
'_ex:1,2c,3d',
'_n:1,2,4d',
'_nx:1,2,4c,5d',
'_n_noop:1,2,3d',
'_nx_noop:1,2,3c,4d',
],
},
files: {
src: [
'**/*.php', // Include all files/
'!node_modules/**', // Exclude node_modules/
'!tests/**', // Exclude tests/
'!vendor/**', // Exclude vendor/
'!tmp/**', // Exclude tmp/
],
expand: true,
},
},
} );
// Load NPM tasks to be used here.
grunt.loadNpmTasks( 'grunt-wp-i18n' );
grunt.loadNpmTasks( 'grunt-checktextdomain' );
grunt.util.linefeed = '\n';
};

View File

@ -1,120 +1,13 @@
# WooCommerce Admin
This is a feature plugin for a modern, javascript-driven WooCommerce Admin experience.
## Prerequisites
[WordPress 5.6 or greater](https://wordpress.org/download/) and [WooCommerce 5.7.0 or greater](https://wordpress.org/plugins/woocommerce/) should be installed prior to activating the WooCommerce Admin feature plugin.
For better debugging, it's also recommended you add `define( 'SCRIPT_DEBUG', true );` to your wp-config. This will load the unminified version of all libraries, and specifically the development build of React.
This is a javascript-driven, React-based admin interface for WooCommerce.
## Development
After cloning the repo, install dependencies:
- `pnpm install` to install JavaScript dependencies.
- `composer install` to gather PHP dependencies.
Now you can build the files using one of these commands:
- `pnpm run build` : Build a production version
- `pnpm run dev` : Build a development version
- `pnpm start` : Build a development version, watch files for changes
- `pnpm run build:release` : Build a WordPress plugin ZIP file (`woocommerce-admin.zip` will be created in the repository root)
- `DRY_RUN=1 pnpm run build:release` : Builds a Wordpress plugin ZIP **without** pushing it to Github and creating a release.
For more helper scripts [see here](./CONTRIBUTING.md#helper-scripts)
For some debugging tools/help [see here](./CONTRIBUTING.md#debugging)
For local development setup using Docker [see here](./docker/wc-admin-wp-env/README.md)
### Typescript
The `npm run ts:check` command will check your TypeScript files for errors, and has been added to `.vscode/tasks.json`.
Running this task in vscode will highlight the errors in your editor file navigator.
If you allow the `npm run ts:check:watch` command to run automatically as configured, it will run in the background and pick up any errors as you save the files.
Note: Even if you don't run this task, the IDE uses its language server to pick up type errors in files that are open. This is only necessary for picking up errors
across the entire repository even when they haven't been opened in the IDE.
### Testing
#### End-to-end tests
Tests live in `./tests/e2e`. An existing build is required prior running, please refer to the section above for steps. E2E tests use the `@woocommerce/e2e-environment` package which hosts a Docker container for testing, by default the container can be accessed at `http://localhost:8084`
All the commands from `@woocommerce/e2e-environment` can be run through `pnpm exec`.
```
# Set up the e2e environment
pnpm i
pnpm exec wc-e2e docker:up
```
Run tests using:
```
pnpm exec wc-e2e test:e2e-dev
```
or in headless mode:
```
pnpm exec wc-e2e test:e2e
```
Run a single test by adding the path to the file name:
```
pnpm exec wc-e2e test:e2e-dev tests/e2e/specs/activate-and-setup/complete-onboarding-wizard.test.ts
```
### Documentation
There is documentation in 2 forms available in the repo. A static set of documentation supported by docsify and also a Storybook containing component documentation for `@woocommerce/components`.
To view the docsify docs locally you can do:
```
pnpm install
cd docs
pnpm exec docsify serve
```
When deployed the docsify docs also host an embedded version of the storybook docs. To generate that and test it locally in docsify you'll need to run:
```
pnpm install
pnpm run docs
cd docs
pnpm exec docsify serve
```
Then navigate to `Components` from the left hand menu in the docs.
If you would like to view the storybook docs hosted standalone, then you can run:
```
pnpm install
pnpm run storybook
```
If you would like to view the storybook docs in right-to-left styling, you can run this instead:
```
pnpm install
pnpm run storybook-rtl
```
Please refer to the [WooCommerce Admin Development](https://github.com/woocommerce/woocommerce/wiki/How-to-set-up-WooCommerce-development-environment#wooCommerce-admin-development)
## End-to-end tests
Please refer to the [WooCommerce End to End Tests](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/tests/e2e/README.md)
## Common Issues
If you're encountering any issue setting things up, chances are we have been there too. Please have a look at our [wiki](https://github.com/woocommerce/woocommerce-admin/wiki/Common-Issues) for a list of common problems.
## Privacy
If you have enabled WooCommerce usage tracking ( option `woocommerce_allow_tracking` ) then, in addition to the tracking described in https://woocommerce.com/usage-tracking/, this plugin also sends information about the actions that site administrators perform to Automattic - see https://automattic.com/privacy/#information-we-collect-automatically for more information.
## Contributing
There are many ways to contribute reporting bugs, adding translations, feature suggestions and fixing bugs. For full details, please see [CONTRIBUTING.md](./CONTRIBUTING.md)
If you're encountering any issue setting things up, chances are we have been there too. Please have a look at our [wiki](https://github.com/woocommerce/woocommerce/wiki/Common-Issues) for a list of common problems.

View File

@ -22,16 +22,7 @@ module.exports = function ( api ) {
],
ignore: [ 'packages/**/node_modules' ],
env: {
production: {
plugins: [
[
'@wordpress/babel-plugin-makepot',
{
output: 'languages/woocommerce-admin.po',
},
],
],
},
production: {},
storybook: {
plugins: [

View File

@ -1,104 +0,0 @@
<?php
/**
* Command line script for merging two .pot files.
*
* @package WooCommerce\Admin
*/
/**
* Get the two file names from the command line.
*/
if ( $argc < 2 ) {
echo "Usage: php -f {$argv[0]} source-file.pot destination-file.pot\n";
exit;
}
for ( $index = 1; $index <= 2; $index++ ) {
if ( ! is_file( $argv[ $index ] ) ) {
echo "File not found: {$argv[ $index ]}\n";
exit;
}
}
/**
* Check whether an output locale has been requested.
*/
if ( isset( $argv[3] ) && 0 === stripos( $argv[3], 'lang=' ) ) {
$locale = substr( $argv[3], 5 );
$target_file = preg_replace( '|\.pot?|', "-{$locale}.po", $argv[2] );
} else {
$target_file = $argv[2];
}
/**
* Parse a .pot file into an array.
*
* @param string $file_name Pot file name.
* @return array
*/
function woocommerce_admin_parse_pot( $file_name ) {
$fh = fopen( $file_name, 'r' );
$originals = array();
$references = array();
$messages = array();
$have_msgid = false;
while ( ! feof( $fh ) ) {
$line = trim( fgets( $fh ) );
if ( ! $line ) {
$message = implode( "\n", $messages );
$originals[ $message ] = $references;
$references = array();
$messages = array();
$have_msgid = false;
$message = '';
continue;
}
if ( 'msgid' == substr( $line, 0, 5 ) ) {
$have_msgid = true;
}
if ( $have_msgid ) {
$messages[] = $line;
} else {
$references[] = $line;
}
}
fclose( $fh );
$message = implode( "\n", $messages );
$originals[ $message ] = $references;
return $originals;
}
// Read the translation files.
$originals_1 = woocommerce_admin_parse_pot( $argv[1] );
$originals_2 = woocommerce_admin_parse_pot( $argv[2] );
// Delete the original sources.
unlink( $argv[1] );
unlink( $argv[2] );
// We don't want two .pot headers in the output.
array_shift( $originals_1 );
$fh = fopen( $target_file, 'w' );
foreach ( $originals_2 as $message => $original ) {
// Use the complete message section to match strings to be translated.
if ( isset( $originals_1[ $message ] ) ) {
$original = array_merge( $original, $originals_1[ $message ] );
unset( $originals_1[ $message ] );
}
fwrite( $fh, implode( "\n", $original ) );
fwrite( $fh, "\n" . $message ."\n\n" );
}
foreach ( $originals_1 as $message => $original ) {
fwrite( $fh, implode( "\n", $original ) );
fwrite( $fh, "\n" . $message ."\n\n" );
}
fclose( $fh );
echo "Created {$target_file}\n";

View File

@ -1,23 +0,0 @@
#!/usr/bin/env bash
# Check for required version
WPCLI_VERSION=`wp cli version | cut -f2 -d' '`
if [ ${WPCLI_VERSION:0:1} -lt "2" -o ${WPCLI_VERSION:0:1} -eq "2" -a ${WPCLI_VERSION:2:1} -lt "1" ]; then
echo WP-CLI version 2.1.0 or greater is required to make JSON translation files
exit
fi
# Substitute JS source references with build references
for T in `find languages -name "*.po"`
do
sed \
-e 's/ client\/[^:]*:/ dist\/app\/index.js:/gp' \
-e 's/ packages\/components[^:]*:/ dist\/components\/index.js:/gp' \
-e 's/ packages\/date[^:]*:/ dist\/date\/index.js:/gp' \
$T | uniq > $T-build
rm $T
mv $T-build $T
done
# Make the JSON files
wp i18n make-json languages --no-purge

View File

@ -5,12 +5,12 @@ Scaffold a modern JavaScript WordPress plugin with WooCommerce tooling.
## Includes
- [wp-scripts](https://github.com/WordPress/gutenberg/tree/master/packages/scripts)
- [WooCommerce Dependency Extraction Webpack Plugin](https://github.com/woocommerce/woocommerce-admin/tree/main/packages/dependency-extraction-webpack-plugin)
- [WooCommerce ESLint Plugin with WordPress Prettier](https://github.com/woocommerce/woocommerce-admin/tree/main/packages/eslint-plugin)
- [WooCommerce Dependency Extraction Webpack Plugin](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/dependency-extraction-webpack-plugin)
- [WooCommerce ESLint Plugin with WordPress Prettier](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/eslint-plugin)
### Usage
At the root of a [WooCommerce Admin](https://github.com/woocommerce/woocommerce-admin) installation, run the create extension command.
At the root of a [WooCommerce Admin](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-admin) installation, run the create extension command.
```
pnpm run create-wc-extension

View File

@ -0,0 +1,4 @@
Significance: minor
Type: Add
Add support for sections in our TaskList class and create a new sectional task list component. #32302

View File

@ -100,6 +100,10 @@ function getMarketingItems( props ) {
link:
'https://woocommerce.com/document/google-listings-and-ads/?utm_medium=product#get-started',
},
activePlugins.includes( 'pinterest-for-woocommerce' ) && {
title: __( 'Set up Pinterest for WooCommerce', 'woocommerce' ),
link: 'https://woocommerce.com/products/pinterest-for-woocommerce/',
},
activePlugins.includes( 'mailchimp-for-woocommerce' ) && {
title: __( 'Connect Mailchimp for WooCommerce', 'woocommerce' ),
link:

View File

@ -121,7 +121,7 @@ Leaderboard.propTypes = {
*/
query: PropTypes.object,
/**
* Which column should be the row header, defaults to the first item (`0`) (see `Table` props).
* An array of arrays of display/value object pairs (see `Table` props).
*/
rows: PropTypes.arrayOf(
PropTypes.arrayOf(

View File

@ -2,13 +2,13 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { COUNTRIES_STORE_NAME, Country } from '@woocommerce/data';
import { COUNTRIES_STORE_NAME, Country, Locale } from '@woocommerce/data';
import { decodeEntities } from '@wordpress/html-entities';
import { escapeRegExp } from 'lodash';
import { escapeRegExp, has } from 'lodash';
import { useEffect, useMemo, useState, useRef } from '@wordpress/element';
import { SelectControl, TextControl } from '@woocommerce/components';
import { Spinner } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useSelect, select as wpDataSelect } from '@wordpress/data';
/**
* Internal dependencies
@ -21,10 +21,24 @@ const storeAddressFields = [
'city',
'countryState',
'postCode',
];
] as const;
type Option = { key: string; label: string };
/**
* Type guard to ensure that the specified locale object has a .required property
*
* @param fieldName field of Locale
* @param locale unknown object to be checked
* @return Boolean indicating if locale has a .required property
*/
const isLocaleRecord = (
fieldName: keyof Locale,
locale: unknown
): locale is Record< keyof Locale, { required: boolean } > => {
return !! locale && has( locale, `${ fieldName }.required` );
};
/**
* Check if a given address field is required for the locale.
*
@ -33,11 +47,11 @@ type Option = { key: string; label: string };
* @return {boolean} Field requirement.
*/
export function isAddressFieldRequired(
fieldName: string,
locale: unknown = {}
fieldName: keyof Locale,
locale: Locale = {}
): boolean {
if ( locale[ fieldName ]?.hasOwnProperty( 'required' ) ) {
return locale[ fieldName ]?.required as boolean;
if ( isLocaleRecord( fieldName, locale ) ) {
return locale[ fieldName ].required;
}
if ( fieldName === 'address_2' ) {
@ -53,18 +67,19 @@ export function isAddressFieldRequired(
* @param {Object} locale The store locale.
* @return {Function} Validator function.
*/
export function getStoreAddressValidator( locale = {} ) {
export function getStoreAddressValidator( locale: Locale = {} ) {
/**
* Form validator.
*
* @param {Object} values Keyed values of all fields in the form.
* @return {Object} Key value of fields and error messages, { myField: 'This field is required' }
*/
return ( values ) => {
return (
values: Record< typeof storeAddressFields[ number ], string >
) => {
const errors: {
[ key: string ]: string;
} = {};
if (
isAddressFieldRequired( 'address_1', locale ) &&
! values.addressLine1.trim().length
@ -100,30 +115,33 @@ export function getStoreAddressValidator( locale = {} ) {
* @return {Object} Select options, { value: 'US:GA', label: 'United States - Georgia' }
*/
export function getCountryStateOptions( countries: Country[] ) {
const countryStateOptions = countries.reduce( ( acc, country ) => {
if ( ! country.states.length ) {
acc.push( {
key: country.code,
label: decodeEntities( country.name ),
const countryStateOptions = countries.reduce(
( acc: Option[], country ) => {
if ( ! country.states.length ) {
acc.push( {
key: country.code,
label: decodeEntities( country.name ),
} );
return acc;
}
const countryStates = country.states.map( ( state ) => {
return {
key: country.code + ':' + state.code,
label:
decodeEntities( country.name ) +
' — ' +
decodeEntities( state.name ),
};
} );
acc.push( ...countryStates );
return acc;
}
const countryStates = country.states.map( ( state ) => {
return {
key: country.code + ':' + state.code,
label:
decodeEntities( country.name ) +
' — ' +
decodeEntities( state.name ),
};
} );
acc.push( ...countryStates );
return acc;
}, [] );
},
[]
);
return countryStateOptions;
}
@ -195,9 +213,7 @@ export function useGetCountryStateAutofill(
): JSX.Element {
const [ autofillCountry, setAutofillCountry ] = useState( '' );
const [ autofillState, setAutofillState ] = useState( '' );
const isAutofillChange: {
current: boolean;
} = useRef();
const isAutofillChange = useRef< boolean >();
// Sync the autofill fields on first render and the countryState value changes.
useEffect( () => {
@ -242,7 +258,7 @@ export function useGetCountryStateAutofill(
const isCountryAbbreviation = autofillCountry.length < 3;
const isStateAbbreviation =
autofillState.length < 3 && !! autofillState.match( /^[\w]+$/ );
let filteredOptions = [];
let filteredOptions: Option[] = [];
if ( autofillCountry.length && autofillState.length ) {
filteredOptions = options.filter( ( option ) =>
@ -337,7 +353,7 @@ export function StoreAddress( {
hasFinishedResolution,
countries,
loadingCountries,
} = useSelect( ( select ) => {
} = useSelect( ( select: typeof wpDataSelect ) => {
const {
getLocale,
getCountries,

View File

@ -7,7 +7,11 @@ import { render, fireEvent } from '@testing-library/react';
/**
* Internal dependencies
*/
import { useGetCountryStateAutofill, getStateFilter } from '../store-address';
import {
isAddressFieldRequired,
useGetCountryStateAutofill,
getStateFilter,
} from '../store-address';
const AutofillWrapper = ( { options, value, onChange } ) => {
const [ values, setValues ] = useState( { countryState: value || '' } );
@ -211,3 +215,28 @@ describe( 'getStateFilter', () => {
}
);
} );
describe( 'isAddressFieldRequired', () => {
it( 'should return true if fieldName is not a key in locale', () => {
expect( isAddressFieldRequired( 'address_1', { foo: 'bar' } ) ).toBe(
true
);
} );
it( 'should return true if locale object marks it as required', () => {
expect(
isAddressFieldRequired( 'address_1', {
address_1: { required: true },
} )
).toBe( true );
} );
it( 'should return false if locale object marks it as not required', () => {
expect(
isAddressFieldRequired( 'address_1', {
address_1: { required: false },
} )
).toBe( false );
} );
it( 'should return false if fieldName is address_2', () => {
expect( isAddressFieldRequired( 'address_2', {} ) ).toBe( false );
} );
} );

View File

@ -6,7 +6,9 @@ import { useEffect, useLayoutEffect, useRef } from '@wordpress/element';
import classnames from 'classnames';
import { decodeEntities } from '@wordpress/html-entities';
import { getSetting } from '@woocommerce/settings';
import { ONBOARDING_STORE_NAME } from '@woocommerce/data';
import { Text, useSlot } from '@woocommerce/experimental';
import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
@ -93,12 +95,18 @@ export const Header = ( { sections, isEmbedded = false, query } ) => {
}
}, [ isEmbedded, sections, siteTitle ] );
const tasksReminderFeature =
window.wcAdminFeatures[ 'tasklist-setup-experiment-1' ];
const { hasTasksReminderFeature } = useSelect( ( select ) => {
const taskLists = select( ONBOARDING_STORE_NAME ).getTaskLists();
return {
hasTasksReminderFeature: taskLists.some(
( list ) => list.id === 'setup_experiment_1'
),
};
} );
return (
<div className={ className } ref={ headerElement }>
{ tasksReminderFeature && (
{ hasTasksReminderFeature && (
<TasksReminderBar
pageTitle={ pageTitle }
updateBodyMargin={ updateBodyMargin }

View File

@ -42,6 +42,7 @@ import { WelcomeModal } from './welcome-modal';
import { useHeadercardExperimentHook } from './hooks/use-headercard-experiment-hook';
import './style.scss';
import '../dashboard/style.scss';
import { getAdminSetting } from '~/utils/admin-settings';
const Tasks = lazy( () =>
import( /* webpackChunkName: "tasks" */ '../tasks' )
@ -63,6 +64,8 @@ export const Layout = ( {
query,
taskListComplete,
hasTaskList,
showingProgressHeader,
isLoadingTaskLists,
shouldShowWelcomeModal,
shouldShowWelcomeFromCalypsoModal,
isTaskListHidden,
@ -140,7 +143,9 @@ export const Layout = ( {
<Column shouldStick={ shouldStickColumns }>
{ ! isLoadingExperimentAssignment &&
! isLoadingTwoColExperimentAssignment &&
! isRunningTaskListExperiment && (
! isRunningTaskListExperiment &&
! isLoadingTaskLists &&
! showingProgressHeader && (
<ActivityHeader
className="your-store-today"
title={ __(
@ -285,8 +290,13 @@ export default compose(
const { getOption, hasFinishedResolution } = select(
OPTIONS_STORE_NAME
);
const { getTaskList, getTaskLists } = select( ONBOARDING_STORE_NAME );
const {
getTaskList,
getTaskLists,
hasFinishedResolution: taskListFinishResolution,
} = select( ONBOARDING_STORE_NAME );
const taskLists = getTaskLists();
const isLoadingTaskLists = ! taskListFinishResolution( 'getTaskLists' );
const welcomeFromCalypsoModalDismissed =
getOption( WELCOME_FROM_CALYPSO_MODAL_DISMISSED_OPTION_NAME ) !==
@ -336,8 +346,12 @@ export default compose(
isBatchUpdating: isNotesRequesting( 'batchUpdateNotes' ),
shouldShowWelcomeModal,
shouldShowWelcomeFromCalypsoModal,
isLoadingTaskLists,
isTaskListHidden: getTaskList( 'setup' )?.isHidden,
hasTaskList: !! taskLists.find( ( list ) => list.isVisible ),
hasTaskList: getAdminSetting( 'visibleTaskListIds', [] ).length > 0,
showingProgressHeader: !! taskLists.find(
( list ) => list.isVisible && list.displayProgressHeader
),
taskListComplete: getTaskList( 'setup' )?.isComplete,
installTimestamp,
installTimestampHasResolved,

View File

@ -79,10 +79,21 @@ const PaymentRecommendations: React.FC = () => {
[ isInstalled ]
);
const supportsWCPayments =
paymentGatewaySuggestions &&
paymentGatewaySuggestions.filter( ( paymentGatewaySuggestion ) => {
return (
paymentGatewaySuggestion.id.indexOf(
'woocommerce_payments'
) === 0
);
} ).length === 1;
const triggeredPageViewRef = useRef( false );
const shouldShowRecommendations =
paymentGatewaySuggestions &&
paymentGatewaySuggestions.length > 0 &&
! supportsWCPayments &&
! isDismissed;
useEffect( () => {

View File

@ -201,7 +201,10 @@ class BusinessDetails extends Component {
const promises = [
this.persistProfileItems( {
business_extensions: businessExtensions,
business_extensions: [
...businessExtensions,
...alreadyActivatedExtensions,
],
} ),
];

View File

@ -1,3 +1,4 @@
@import 'node_modules/@wordpress/base-styles/colors.native';
// By using CSS variables, we can switch the spacing rhythm using a single media query.
:root {
--large-gap: 40px;
@ -37,6 +38,14 @@
max-width: 100%;
line-height: 1;
}
.components-panel__body > .components-panel__body-title,
.woocommerce-experimental-list__item,
.woocommerce-inbox-message {
&:hover {
background: $gray-0;
}
}
}
body.woocommerce-page {

View File

@ -19,9 +19,9 @@ $progress-complete-color: #007cba;
appearance: none;
border: 1px solid #ddd;
border-radius: 16px;
height: 10px;
height: 12px;
width: 100%;
margin-bottom: 20px;
margin-bottom: 0;
// Firefox
& {
@ -49,5 +49,6 @@ $progress-complete-color: #007cba;
.woocommerce-card__menu {
position: absolute;
right: 0;
top: 7px;
}
}

View File

@ -4,7 +4,11 @@
import { __, sprintf } from '@wordpress/i18n';
import { useMemo } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { ONBOARDING_STORE_NAME, TaskListType } from '@woocommerce/data';
import {
getVisibleTasks,
ONBOARDING_STORE_NAME,
TaskListType,
} from '@woocommerce/data';
import { getSetting } from '@woocommerce/settings';
/**
@ -20,37 +24,38 @@ type ProgressHeaderProps = {
export const ProgressHeader: React.FC< ProgressHeaderProps > = ( {
taskListId,
} ) => {
const { loading, tasksCount, completedCount, hasVisitedTasks } = useSelect(
( select ) => {
const taskList: TaskListType = select(
ONBOARDING_STORE_NAME
).getTaskList( taskListId );
const finishedResolution = select(
ONBOARDING_STORE_NAME
).hasFinishedResolution( 'getTaskList', [ taskListId ] );
const nowTimestamp = Date.now();
const visibleTasks = taskList?.tasks.filter(
( task ) =>
! task.isDismissed &&
( ! task.isSnoozed || task.snoozedUntil < nowTimestamp )
);
const {
loading,
tasksCount,
completedCount,
hasVisitedTasks,
disabledCompletedCount,
} = useSelect( ( select ) => {
const taskList: TaskListType = select(
ONBOARDING_STORE_NAME
).getTaskList( taskListId );
const finishedResolution = select(
ONBOARDING_STORE_NAME
).hasFinishedResolution( 'getTaskList', [ taskListId ] );
const visibleTasks = getVisibleTasks( taskList?.tasks );
return {
loading: ! finishedResolution,
tasksCount: visibleTasks?.length,
completedCount: visibleTasks?.filter(
( task ) => task.isComplete
).length,
hasVisitedTasks:
visibleTasks?.filter( ( task ) => task.isVisited ).length >
0,
};
}
);
return {
loading: ! finishedResolution,
tasksCount: visibleTasks?.length,
completedCount: visibleTasks?.filter( ( task ) => task.isComplete )
.length,
disabledCompletedCount: visibleTasks?.filter(
( task ) => task.isComplete && task.isDisabled
).length,
hasVisitedTasks:
visibleTasks?.filter( ( task ) => task.isVisited ).length > 0,
};
} );
const progressTitle = useMemo( () => {
if (
( ! hasVisitedTasks && completedCount < 2 ) ||
( ! hasVisitedTasks &&
completedCount < 2 + disabledCompletedCount ) ||
completedCount === tasksCount
) {
const siteTitle = getSetting( 'siteTitle' );
@ -71,7 +76,7 @@ export const ProgressHeader: React.FC< ProgressHeaderProps > = ( {
return __( 'You are almost there', 'woocommerce' );
}, [ completedCount, hasVisitedTasks ] );
if ( loading || completedCount === tasksCount ) {
if ( loading ) {
return null;
}
@ -85,22 +90,26 @@ export const ProgressHeader: React.FC< ProgressHeaderProps > = ( {
<h1 className="woocommerce-task-progress-header__title">
{ progressTitle }
</h1>
<p>
{ sprintf(
/* translators: 1: completed tasks, 2: total tasks */
__(
'Follow these steps to start selling quickly. %1$d out of %2$d complete.',
'woocommerce'
),
completedCount,
tasksCount
) }
</p>
<progress
className="woocommerce-task-progress-header__progress-bar"
max={ tasksCount }
value={ completedCount || 0 }
/>
{ completedCount !== tasksCount ? (
<>
<p>
{ sprintf(
/* translators: 1: completed tasks, 2: total tasks */
__(
'Follow these steps to start selling quickly. %1$d out of %2$d complete.',
'woocommerce'
),
completedCount,
tasksCount
) }
</p>
<progress
className="woocommerce-task-progress-header__progress-bar"
max={ tasksCount }
value={ completedCount || 0 }
/>
</>
) : null }
</div>
</div>
);

View File

@ -24,7 +24,8 @@ export const Action = ( {
markConfigured,
onSetUp = () => {},
onSetupCallback,
setupButtonText = __( 'Set up', 'woocommerce' ),
setupButtonText = __( 'Get started', 'woocommerce' ),
externalLink = null,
} ) => {
const [ isBusy, setIsBusy ] = useState( false );
@ -41,6 +42,11 @@ export const Action = ( {
selected: getPluginTrackKey( id ),
} );
if ( ! hasPlugins && externalLink ) {
window.location.href = externalLink;
return;
}
if ( onSetupCallback ) {
setIsBusy( true );
await new Promise( onSetupCallback )
@ -84,17 +90,19 @@ export const Action = ( {
</Button>
);
const EnableButton = () => (
<Button
className={ classes }
isSecondary
onClick={ () => markConfigured( id ) }
>
{ __( 'Enable', 'woocommerce' ) }
</Button>
);
if ( ! hasSetup ) {
if ( ! isEnabled ) {
return (
<Button
className={ classes }
isSecondary
onClick={ () => markConfigured( id ) }
>
{ __( 'Enable', 'woocommerce' ) }
</Button>
);
return <EnableButton />;
}
return <ManageButton />;
@ -110,6 +118,10 @@ export const Action = ( {
}
if ( ! needsSetup ) {
if ( ! isEnabled ) {
return <EnableButton />;
}
return <ManageButton />;
}

View File

@ -4,8 +4,10 @@
import classnames from 'classnames';
import { Fragment } from '@wordpress/element';
import { CardBody, CardMedia, CardDivider } from '@wordpress/components';
import { RecommendedRibbon, SetupRequired } from '@woocommerce/onboarding';
import { SetupRequired } from '@woocommerce/onboarding';
import { Pill } from '@woocommerce/components';
import { Text, useSlot } from '@woocommerce/experimental';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
@ -15,7 +17,7 @@ import './List.scss';
export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
const {
image,
image_72x72: image72x72,
content,
id,
plugins = [],
@ -27,6 +29,7 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
requiredSettings,
settingsUrl: manageUrl,
is_local_partner: isLocalPartner,
external_link: externalLink,
} = paymentGateway;
const connectSlot = useSlot(
@ -39,9 +42,9 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
Boolean( setupSlot?.fills?.length );
const hasSetup = Boolean(
plugins.length || requiredSettings.length || hasFills
plugins.length || requiredSettings.length || hasFills || externalLink
);
const showRecommendedRibbon = isRecommended && needsSetup;
const showRecommended = isRecommended && needsSetup;
const classes = classnames(
'woocommerce-task-payment',
@ -57,14 +60,20 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
className={ classes }
>
<CardMedia isBorderless>
<img src={ image } alt={ title } />
<img src={ image72x72 } alt={ title } />
</CardMedia>
<div className="woocommerce-task-payment__description">
{ showRecommendedRibbon && (
<RecommendedRibbon isLocalPartner={ isLocalPartner } />
) }
<Text as="h3" className="woocommerce-task-payment__title">
{ title }
<span>{ title }</span>
{ showRecommended && (
<Pill
className={ ! isLocalPartner && 'pill-green' }
>
{ isLocalPartner
? __( 'Local Partner', 'woocommerce' )
: __( 'Recommended', 'woocommerce' ) }
</Pill>
) }
{ isInstalled && needsSetup && !! plugins.length && (
<SetupRequired />
) }
@ -85,6 +94,7 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
isRecommended={ isRecommended }
isLoading={ loading }
markConfigured={ markConfigured }
externalLink={ externalLink }
/>
</div>
</CardBody>

View File

@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { Card, CardHeader } from '@wordpress/components';
import { Card, CardHeader, CardFooter } from '@wordpress/components';
/**
* Internal dependencies
@ -15,10 +15,11 @@ export const List = ( {
markConfigured,
recommendation,
paymentGateways,
footerLink,
} ) => {
return (
<Card>
<CardHeader as="h2">{ heading }</CardHeader>
{ heading && <CardHeader as="h2">{ heading }</CardHeader> }
{ paymentGateways.map( ( paymentGateway ) => {
const { id } = paymentGateway;
return (
@ -30,6 +31,9 @@ export const List = ( {
/>
);
} ) }
{ footerLink && (
<CardFooter isBorderless>{ footerLink }</CardFooter>
) }
</Card>
);
};

View File

@ -6,14 +6,15 @@
overflow: hidden;
.components-card__media {
width: 170px;
width: 85px;
flex-shrink: 0;
align-self: flex-start;
img,
svg,
.is-placeholder {
margin: auto;
max-width: 100px;
max-width: 36px;
display: block;
}
@ -41,6 +42,15 @@
color: $studio-gray-80;
margin-top: 0;
margin-bottom: $gap-smaller;
.woocommerce-pill {
margin-left: 8px;
&.pill-green {
color: #008a20;
border-color: #008a20;
}
}
}
.woocommerce-task-payment__content {

View File

@ -49,7 +49,7 @@ describe( 'PaymentGatewaySuggestions > List', () => {
expect( queryByRole( 'button' ) ).toHaveTextContent( 'Enable' );
} );
it( 'should display the "Set up" button when setup is required', () => {
it( 'should display the "Get started" button when setup is required', () => {
const props = {
...defaultProps,
paymentGateways: [
@ -63,7 +63,7 @@ describe( 'PaymentGatewaySuggestions > List', () => {
const { queryByRole } = render( <List { ...props } /> );
expect( queryByRole( 'button' ) ).toHaveTextContent( 'Set up' );
expect( queryByRole( 'button' ) ).toHaveTextContent( 'Get started' );
} );
it( 'should display the SetupRequired component when appropriate', () => {
@ -138,7 +138,7 @@ describe( 'PaymentGatewaySuggestions > List', () => {
expect( queryByText( 'Recommended' ) ).not.toBeInTheDocument();
} );
it( 'should display Manage button if not enabled and does have setup', () => {
it( 'should display Manage button if enabled and does have setup', () => {
const props = {
...defaultProps,
paymentGateways: [
@ -180,6 +180,7 @@ describe( 'PaymentGatewaySuggestions > List', () => {
...mockGateway,
plugins: [ 'nope' ],
needsSetup: false,
enabled: true,
},
],
};

View File

@ -156,7 +156,7 @@ export const Configure = ( { markConfigured, paymentGateway } ) => {
</p>
) }
<Button isPrimary href={ settingsUrl }>
{ __( 'Set up', 'woocommerce' ) }
{ __( 'Get started', 'woocommerce' ) }
</Button>
</>
);

View File

@ -81,7 +81,7 @@ describe( 'Configure', () => {
const { container } = render( <Configure { ...props } /> );
const button = container.querySelector( 'a' );
expect( button.textContent ).toBe( 'Set up' );
expect( button.textContent ).toBe( 'Get started' );
expect( button.href ).toBe( mockGateway.settingsUrl );
} );
} );

View File

@ -0,0 +1,40 @@
/**
* External dependencies
*/
import { Button } from '@wordpress/components';
import ChevronUpIcon from 'gridicons/dist/chevron-up';
import ChevronDownIcon from 'gridicons/dist/chevron-down';
import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import './Toggle.scss';
export const Toggle = ( { children, heading, onToggle } ) => {
const [ isShow, setIsShow ] = useState( false );
const onClick = () => {
onToggle( isShow );
setIsShow( ! isShow );
};
return (
<div className="toggle">
<Button
isTertiary
onClick={ onClick }
aria-expanded={ isShow }
frameBorder={ 0 }
className="toggle-button"
>
{ heading }
{ isShow ? (
<ChevronUpIcon size={ 18 } />
) : (
<ChevronDownIcon size={ 18 } />
) }
</Button>
{ isShow ? children : null }
</div>
);
};

View File

@ -0,0 +1,9 @@
.woocommerce-task-payments {
.toggle-button {
margin: $gap-small 0;
.gridicon {
margin-left: 4px;
}
}
}

View File

@ -0,0 +1 @@
export { Toggle } from './Toggle';

View File

@ -7,26 +7,44 @@ import {
OPTIONS_STORE_NAME,
ONBOARDING_STORE_NAME,
PAYMENT_GATEWAYS_STORE_NAME,
SETTINGS_STORE_NAME,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useMemo, useCallback, useEffect } from '@wordpress/element';
import { registerPlugin } from '@wordpress/plugins';
import { WooOnboardingTask } from '@woocommerce/onboarding';
import { getNewPath } from '@woocommerce/navigation';
import { getAdminLink } from '@woocommerce/settings';
import { Button } from '@wordpress/components';
import ExternalIcon from 'gridicons/dist/external';
/**
* Internal dependencies
*/
import { List, Placeholder as ListPlaceholder } from './components/List';
import { Setup, Placeholder as SetupPlaceholder } from './components/Setup';
import { Toggle } from './components/Toggle/Toggle';
import { WCPaySuggestion } from './components/WCPay';
import { getPluginSlug } from '~/utils';
import { getCountryCode } from '~/dashboard/utils';
import './plugins/Bacs';
import './payment-gateway-suggestions.scss';
const comparePaymentGatewaysByPriority = ( a, b ) =>
a.recommendation_priority - b.recommendation_priority;
const isGatewayWCPay = ( gateway ) =>
gateway.plugins?.length === 1 &&
gateway.plugins[ 0 ] === 'woocommerce-payments';
const isGatewayOtherCategory = ( gateway, countryCode ) =>
gateway.category_other &&
gateway.category_other.indexOf( countryCode ) !== -1;
const isGatewayAdditionalCategory = ( gateway, countryCode ) =>
gateway.category_additional &&
gateway.category_additional.indexOf( countryCode ) !== -1;
export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
const { updatePaymentGateway } = useDispatch( PAYMENT_GATEWAYS_STORE_NAME );
const {
@ -34,7 +52,10 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
paymentGatewaySuggestions,
installedPaymentGateways,
isResolving,
countryCode,
} = useSelect( ( select ) => {
const { getSettings } = select( SETTINGS_STORE_NAME );
const { general: settings = {} } = getSettings( 'general' );
return {
getPaymentGateway: select( PAYMENT_GATEWAYS_STORE_NAME )
.getPaymentGateway,
@ -48,6 +69,7 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
paymentGatewaySuggestions: select(
ONBOARDING_STORE_NAME
).getPaymentGatewaySuggestions(),
countryCode: getCountryCode( settings.woocommerce_default_country ),
};
}, [] );
@ -179,7 +201,28 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
return gateway;
}, [ isResolving, query, paymentGateways ] );
const [ wcPayGateway, enabledGateways, additionalGateways ] = useMemo(
const isWCPayOrOtherCategoryDoneSetup = useMemo( () => {
for ( const [ , gateway ] of paymentGateways.entries() ) {
if ( ! gateway.installed || gateway.needsSetup ) {
continue;
}
if ( isGatewayWCPay( gateway ) ) {
return true;
}
if ( isGatewayOtherCategory( gateway, countryCode ) ) {
return true;
}
}
return false;
}, [ countryCode, paymentGateways ] );
const isWCPaySupported =
Array.from( paymentGateways.values() ).findIndex( isGatewayWCPay ) !==
-1;
const [ wcPayGateway, offlineGateways, additionalGateways ] = useMemo(
() =>
Array.from( paymentGateways.values() )
.sort( ( a, b ) => {
@ -196,18 +239,36 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
} )
.reduce(
( all, gateway ) => {
const [ wcPay, enabled, additional ] = all;
const [ wcPay, offline, additional ] = all;
// WCPay is handled separately when not installed and configured
if (
gateway.plugins?.length === 1 &&
gateway.plugins[ 0 ] === 'woocommerce-payments' &&
isGatewayWCPay( gateway ) &&
! ( gateway.installed && ! gateway.needsSetup )
) {
wcPay.push( gateway );
} else if ( gateway.is_offline ) {
offline.push( gateway );
} else if ( gateway.enabled ) {
enabled.push( gateway );
} else {
// Enabled gateways should be ignored.
} else if ( isWCPayOrOtherCategoryDoneSetup ) {
// If WCPay or "other" gateway is enabled in an WCPay-eligible country, only
// allow to list "additional" gateways.
if (
isGatewayAdditionalCategory(
gateway,
countryCode
)
) {
additional.push( gateway );
}
} else if ( ! isWCPaySupported ) {
// When WCPay-ineligible, just show all gateways.
additional.push( gateway );
} else if (
isGatewayOtherCategory( gateway, countryCode )
) {
// When nothing is set up and eligible for WCPay, only show "other" gateways.
additional.push( gateway );
}
@ -215,9 +276,26 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
},
[ [], [], [] ]
),
[ paymentGateways ]
[
countryCode,
isWCPaySupported,
isWCPayOrOtherCategoryDoneSetup,
paymentGateways,
]
);
const trackSeeMore = () => {
recordEvent( 'tasklist_payment_see_more', {} );
};
const trackToggle = ( isShow ) => {
recordEvent( 'tasklist_payment_show_toggle', {
toggle: isShow ? 'hide' : 'show',
payment_method_count:
offlineGateways.length + additionalGateways.length,
} );
};
if ( query.id && ! currentGateway ) {
return <SetupPlaceholder />;
}
@ -231,32 +309,62 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
);
}
const additionalSection = !! additionalGateways.length && (
<List
heading={
! wcPayGateway.length &&
__( 'Choose a payment provider', 'woocommerce' )
}
recommendation={ recommendation }
paymentGateways={ additionalGateways }
markConfigured={ markConfigured }
footerLink={
! isWCPayOrOtherCategoryDoneSetup && (
<Button
href={ getAdminLink(
'admin.php?page=wc-addons&section=payment-gateways'
) }
target="_blank"
onClick={ trackSeeMore }
isTertiary
>
{ __( 'See more', 'woocommerce' ) }
<ExternalIcon size={ 18 } />
</Button>
)
}
></List>
);
const offlineSection = !! offlineGateways.length && (
<List
heading={ __( 'Offline payment methods', 'woocommerce' ) }
recommendation={ recommendation }
paymentGateways={ offlineGateways }
markConfigured={ markConfigured }
/>
);
return (
<div className="woocommerce-task-payments">
{ ! paymentGateways.size && <ListPlaceholder /> }
{ !! wcPayGateway.length && (
<WCPaySuggestion paymentGateway={ wcPayGateway[ 0 ] } />
) }
{ !! enabledGateways.length && (
<List
heading={ __( 'Enabled payment gateways', 'woocommerce' ) }
recommendation={ recommendation }
paymentGateways={ enabledGateways }
/>
) }
{ !! additionalGateways.length && (
<List
heading={ __(
'Additional payment gateways',
'woocommerce'
) }
recommendation={ recommendation }
paymentGateways={ additionalGateways }
markConfigured={ markConfigured }
/>
{ wcPayGateway.length ? (
<>
<WCPaySuggestion paymentGateway={ wcPayGateway[ 0 ] } />
<Toggle
heading={ __( 'Other payment methods', 'woocommerce' ) }
onToggle={ trackToggle }
>
{ additionalSection }
{ offlineSection }
</Toggle>
</>
) : (
<>
{ additionalSection }
{ offlineSection }
</>
) }
</div>
);

View File

@ -22,6 +22,14 @@
margin: 0;
}
.components-card__footer {
a.components-button {
.gridicon {
margin-left: 4px;
}
}
}
.woocommerce-task-payment__recommended-pill {
border: 1px solid $studio-gray-5;
border-radius: 28px;
@ -38,6 +46,10 @@
.components-card__divider:last-child {
display: none;
}
.woocommerce-task-payment-wcpay {
margin-bottom: 0;
}
}
// @todo This can be migrated into the PaymentMethod component once the payment-gateway-suggestions feature is enabled.

View File

@ -31,6 +31,8 @@ const paymentGatewaySuggestions = [
plugins: [ 'woocommerce-gateway-stripe' ],
is_visible: true,
recommendation_priority: 3,
category_other: [ 'US' ],
category_additional: [],
},
{
id: 'ppcp-gateway',
@ -41,6 +43,8 @@ const paymentGatewaySuggestions = [
'http://localhost:8888/wp-content/plugins/woocommerce/assets/images/paypal.png',
plugins: [ 'woocommerce-paypal-payments' ],
is_visible: true,
category_other: [ 'US' ],
category_additional: [ 'US' ],
},
{
id: 'cod',
@ -49,6 +53,7 @@ const paymentGatewaySuggestions = [
image:
'http://localhost:8888/wp-content/plugins/woocommerce-admin/images/onboarding/cod.svg',
is_visible: true,
is_offline: true,
},
{
id: 'bacs',
@ -57,6 +62,7 @@ const paymentGatewaySuggestions = [
image:
'http://localhost:8888/wp-content/plugins/woocommerce-admin/images/onboarding/bacs.svg',
is_visible: true,
is_offline: true,
},
{
id: 'woocommerce_payments:non-us',
@ -80,11 +86,17 @@ const paymentGatewaySuggestions = [
'http://localhost:8888/wp-content/plugins/woocommerce-admin/images/onboarding/eway.png',
plugins: [ 'woocommerce-gateway-eway' ],
is_visible: true,
category_other: [ 'US' ],
category_additional: [ 'US' ],
},
];
const paymentGatewaySuggestionsWithoutWCPay = paymentGatewaySuggestions.filter(
( p ) => p.title !== 'WooCommerce Payments'
);
describe( 'PaymentGatewaySuggestions', () => {
test( 'should render payment gateway lists', () => {
test( 'should render only WCPay if its suggested', () => {
const onComplete = jest.fn();
const query = {};
useSelect.mockImplementation( () => ( {
@ -109,6 +121,38 @@ describe( 'PaymentGatewaySuggestions', () => {
( e ) => e.textContent
);
expect( paymentTitles ).toEqual( [] );
expect(
container.getElementsByTagName( 'title' )[ 0 ].textContent
).toBe( 'WooCommerce Payments' );
} );
test( 'should render all payment gateways if no WCPay', () => {
const onComplete = jest.fn();
const query = {};
useSelect.mockImplementation( () => ( {
isResolving: false,
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions: paymentGatewaySuggestionsWithoutWCPay,
installedPaymentGateways: [],
} ) );
const { container } = render(
<PaymentGatewaySuggestions
onComplete={ onComplete }
query={ query }
/>
);
const paymentTitleElements = container.querySelectorAll(
'.woocommerce-task-payment__title > span:first-child'
);
const paymentTitles = Array.from( paymentTitleElements ).map(
( e ) => e.textContent
);
expect( paymentTitles ).toEqual( [
'Stripe',
'PayPal Payments',
@ -116,10 +160,6 @@ describe( 'PaymentGatewaySuggestions', () => {
'Cash on delivery',
'Direct bank transfer',
] );
expect(
container.getElementsByTagName( 'title' )[ 0 ].textContent
).toBe( 'WooCommerce Payments' );
} );
test( 'should the payment gateway offline options at the bottom', () => {
@ -128,7 +168,7 @@ describe( 'PaymentGatewaySuggestions', () => {
useSelect.mockImplementation( () => ( {
isResolving: false,
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions,
paymentGatewaySuggestions: paymentGatewaySuggestionsWithoutWCPay,
installedPaymentGateways: [],
} ) );
@ -154,7 +194,7 @@ describe( 'PaymentGatewaySuggestions', () => {
useSelect.mockImplementation( () => ( {
isResolving: false,
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions,
paymentGatewaySuggestions: paymentGatewaySuggestionsWithoutWCPay,
installedPaymentGateways: [
{
id: 'ppcp-gateway',
@ -178,13 +218,56 @@ describe( 'PaymentGatewaySuggestions', () => {
expect( getByText( 'Finish setup' ) ).toBeInTheDocument();
} );
test( 'should record event correctly when finish setup is clicked', () => {
test( 'should show "category_additional" gateways only after WCPay is set up', () => {
const onComplete = jest.fn();
const query = {};
useSelect.mockImplementation( () => ( {
isResolving: false,
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions,
installedPaymentGateways: [
{
id: 'woocommerce_payments',
title: 'WooCommerce Payments',
plugins: [ 'woocommerce-payments' ],
is_visible: true,
needs_setup: false,
},
],
countryCode: 'US',
} ) );
const { container } = render(
<PaymentGatewaySuggestions
onComplete={ onComplete }
query={ query }
/>
);
const paymentTitleElements = container.querySelectorAll(
'.woocommerce-task-payment__title'
);
const paymentTitles = Array.from( paymentTitleElements ).map(
( e ) => e.textContent
);
expect( paymentTitles ).toEqual( [
'PayPal Payments',
'Eway',
'Cash on delivery',
'Direct bank transfer',
] );
} );
test( 'should record event correctly when finish setup is clicked', () => {
const onComplete = jest.fn();
const query = {};
useSelect.mockImplementation( () => ( {
isResolving: false,
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions: paymentGatewaySuggestionsWithoutWCPay,
installedPaymentGateways: [
{
id: 'ppcp-gateway',
@ -211,4 +294,62 @@ describe( 'PaymentGatewaySuggestions', () => {
selected: 'ppcp_gateway',
} );
} );
test( 'should record event correctly when other payment methods is clicked', () => {
const onComplete = jest.fn();
const query = {};
useSelect.mockImplementation( () => ( {
isResolving: false,
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions,
installedPaymentGateways: [],
countryCode: 'US',
} ) );
render(
<PaymentGatewaySuggestions
onComplete={ onComplete }
query={ query }
/>
);
fireEvent.click( screen.getByText( 'Other payment methods' ) );
// By default it's hidden, so when toggle it shows.
// Second call after "tasklist_payments_options".
expect(
recordEvent.mock.calls[ recordEvent.mock.calls.length - 1 ]
).toEqual( [
'tasklist_payment_show_toggle',
{
toggle: 'show',
payment_method_count: paymentGatewaySuggestions.length - 1, // Minus one for WCPay since it's not counted in "other payment methods".
},
] );
} );
test( 'should record event correctly when see more is clicked', () => {
const onComplete = jest.fn();
const query = {};
useSelect.mockImplementation( () => ( {
isResolving: false,
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions,
installedPaymentGateways: [],
countryCode: 'US',
} ) );
render(
<PaymentGatewaySuggestions
onComplete={ onComplete }
query={ query }
/>
);
fireEvent.click( screen.getByText( 'Other payment methods' ) );
fireEvent.click( screen.getByText( 'See more' ) );
expect(
recordEvent.mock.calls[ recordEvent.mock.calls.length - 1 ]
).toEqual( [ 'tasklist_payment_see_more', {} ] );
} );
} );

Some files were not shown because too many files have changed in this diff Show More