Skip to content

Commit

Permalink
Merge pull request #256 from Pinelab-studio/feat/order-client-loading…
Browse files Browse the repository at this point in the history
…-states

Order Client Loading States
  • Loading branch information
martijnvdbrug authored Sep 28, 2023
2 parents 5b6d45f + 01f5daa commit 32ccac7
Show file tree
Hide file tree
Showing 8 changed files with 2,780 additions and 234 deletions.
4 changes: 3 additions & 1 deletion packages/vendure-order-client/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
// TODO set correct version number + date and the changes you've made connected to the PR. See this example for the correct format: https://github.com/Pinelab-studio/pinelab-vendure-plugins/blob/main/packages/vendure-plugin-invoices/CHANGELOG.md
# 2.1.0 (2023-09-20)

- Added loading states for currentUser and activeOrder store ([#256](https://github.com/Pinelab-studio/pinelab-vendure-plugins/pull/256))
22 changes: 16 additions & 6 deletions packages/vendure-order-client/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Vendure Client

A typed, extensible, framework-agnostic client for managing active orders and checkout with Vendure. This package aims to do most of the logic related to active order and checkout management, so that you can focus on presentation with your favorite framework.
A typed, extensible, framework-agnostic client for managing active orders and checkout with Vendure. This package aims to do most of the default logic related to active order and checkout management, so that you can focus on presentation with your favorite framework.

- Sensible, but extendable default GraphQL fields.
- Active order state management.
Expand All @@ -16,18 +16,28 @@ This package should only be used client side, i.e. for fetching an active order,

## Getting started

```ts
This is a Vue.js example, but integrations for React and more are available for @nanostores

```vue
<template>
<div>
<h1 v-if="activeOrder.loading">Loading...</h1>
<h1 v-if="activeOrder.error">Something went wrong!</h1>
<h1 v-if="activeOrder.data">Active order: {{ data.code }}</h1>
</div>
</template>
<script setup lang="ts">
import { VendureOrderClient } from 'vendure-order-client';
import { useStore } from '@nanostores/vue';
const client = new VendureOrderClient(
'http://localhost:3050/shop-api',
'your-channel-token'
);
await client.addItemToOrder('some-id', 1);

// Make this reactive with one of Nanostores' integrations
const total = client.activeOrder.totalWithTax;
const activeOrder = useStore(client.$activeOrder);
await client.getActiveOrder();
</script>
```

## Add your own graphql fields
Expand Down
6 changes: 5 additions & 1 deletion packages/vendure-order-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pinelab/vendure-order-client",
"version": "2.0.0",
"version": "2.1.0",
"description": "A tiny, framework agnostic client for managing active orders and checkout with Vendure.",
"author": "Martijn van de Brug <[email protected]>",
"homepage": "https://pinelab-plugins.com/",
Expand Down Expand Up @@ -32,5 +32,9 @@
"mitt": "^3.0.0",
"nanostores": "^0.9.2"
},
"devDependencies": {
"@nanostores/vue": "^0.10.0",
"@vue/cli": "^5.0.8"
},
"gitHead": "476f36da3aafea41fbf21c70774a30306f1d238f"
}
2 changes: 2 additions & 0 deletions packages/vendure-order-client/src/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ export class GraphqlQueries {
}
}
}
${this.CURRENT_USER_FIELDS}
`;

LOGIN = gql`
Expand All @@ -355,5 +356,6 @@ export class GraphqlQueries {
}
}
}
${this.CURRENT_USER_FIELDS}
`;
}
68 changes: 68 additions & 0 deletions packages/vendure-order-client/src/store-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { MapStore } from 'nanostores';
import { ErrorCode, ErrorResult } from './graphql-generated-types';

/**
* Interface defining loading and error states per store
*/
export interface StateStore<T> {
loading: boolean;
error: ErrorResult | undefined;
data: T;
}

/**
* Set result as data if not ErrorResult, otherwise set as error in store
*/
export function setResult<T>(
store: MapStore<StateStore<T>>,
result: unknown | ErrorResult
): void {
store.setKey('loading', false);
if ((result as ErrorResult)?.errorCode) {
const errorResult = result as ErrorResult;
store.setKey('error', {
errorCode: errorResult.errorCode,
message: errorResult.message,
});
} else {
store.setKey('data', result as T);
}
}

/**
* Handle loading and error state for given store:
* - Sets loading to true
* - Executes given function
* - Sets loading to false
* - Returns result of function
*
* If an error is caught, it's set as error in the store and thrown.
* Loading state is always set back to false
*/
export function HandleLoadingState(storeName: string) {
return function (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value; // Save a reference to the original method
descriptor.value = async function (this: any, ...args: any[]) {
const store: MapStore<StateStore<any>> = this[storeName];
store.setKey('loading', true);
if (!store) {
throw new Error(`Store ${storeName} not found`);
}
try {
const result = await originalMethod.apply(this, args);
return result;
} catch (e: any) {
store.setKey('error', {
errorCode: ErrorCode.UnknownError,
message: e?.message,
});
} finally {
store.setKey('loading', false);
}
};
};
}
Loading

0 comments on commit 32ccac7

Please sign in to comment.