Skip to content

Commit

Permalink
feat: implement flexible identifier schemes
Browse files Browse the repository at this point in the history
Signed-off-by: Nam Hoang <[email protected]>
  • Loading branch information
namhoang1604 committed Nov 22, 2024
1 parent 35f5400 commit c2d9322
Show file tree
Hide file tree
Showing 36 changed files with 9,091 additions and 287 deletions.
748 changes: 736 additions & 12 deletions app-config.json

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions documentation/docs/mock-apps/common/construct-ai-data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
sidebar_position: 57
title: Construct Application Identifier Data
---

import Disclaimer from '../.././\_disclaimer.mdx';

<Disclaimer />

## Description

The `constructAiData` object defines the schema for constructing event data for getting Application Identifier (AI) data. It will be used to fetch the AI data from the JSON form or the credential object which are not explicitly defined the data model.

### Example

```json
{
"primary": {
"ai": "01",
"path": "/registeredId"
},
"qualifiers": [
{
"ai": "21",
"path": "/serialNumber"
},
{
"ai": "10",
"path": "/batchNumber"
}
]
}
```

### Definitions

| Property | Required | Description | Type |
| ---------- | :------: | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| primary | Yes | The primary AI that defines the AI code and the path for primary AI value | [AI config](/docs/mock-apps/common/construct-ai-data#ai-config) |
| qualifiers | No | The list of qualifiers that define the AI code and the path for qualifier AI value | [AI config](/docs/mock-apps/common/construct-ai-data#ai-config)[] |

#### AI config

| Property | Required | Description | Type |
| -------- | :------: | ----------------------------------------------------------------------- | ------ |
| ai | Yes | The AI code that defines the AI data | String |
| path | Yes | The JSON pointer path to extract the AI data from the credential object | String |
34 changes: 19 additions & 15 deletions documentation/docs/mock-apps/common/identifier-key-path.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import Disclaimer from '../.././\_disclaimer.mdx';

## Description

The `IdentifierKeyPath` is a property of services that interact with the data issued to get the identifier to be used for the [IDR](/docs/mock-apps/common/idr) registration. It can be a JSON path of the identifier of the data issued or an object that contains the function `concatService` and the `args` to be used to get the identifier.
The `IdentifierKeyPath` can be an object or a string that defines the path to extract the identifier data from the [Json Form component](/docs/mock-apps/components/json-form). When the `identifierKeyPath` is a string, it should be a link resolver URL. When the `identifierKeyPath` is an object, it should contain AI codes and JSON pointer paths to extract the appropriate data for identifier generation.

## Example

```json
{
"identifierKeyPath": "/eventID"
"identifierKeyPath": "/id" // Example of a link resolver URL: https://example.com/gs1/01/0123456789123/21/123456/10/123456
}
```

Expand All @@ -24,22 +24,26 @@ or
```json
{
"identifierKeyPath": {
"function": "concatService",
"args": [
{ "type": "text", "value": "(01)" },
{ "type": "path", "value": "/productIdentifier/0/identifierValue" },
{ "type": "text", "value": "(10)" },
{ "type": "path", "value": "/batchIdentifier/0/identifierValue" },
{ "type": "text", "value": "(21)" },
{ "type": "path", "value": "/itemIdentifier/0/identifierValue" }
"primary": {
"ai": "01",
"path": "/registeredId"
},
"qualifiers": [
{
"ai": "21",
"path": "/serialNumber"
},
{
"ai": "10",
"path": "/batchNumber"
}
]
}
}
```

## Definition for object
## Definition

| Property | Required | Description | Type |
| -------- | :------: | ------------------------------------------------ | ------ |
| function | Yes | The concat function supported | String |
| args | Yes | The array of object that can be `text` or `path` | Array |
| Property | Required | Description | Type |
| ----------------- | :------: | --------------------------------------- | ------------------------------------------------------------ |
| identifierKeyPath | Yes | The path to extract the identifier data | String or [AIData](/docs/mock-apps/common/construct-ai-data) |
40 changes: 28 additions & 12 deletions documentation/docs/mock-apps/components/barcode-generator.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ sidebar_position: 18
title: Barcode Generator
---

import Disclaimer from '../../_disclaimer.mdx';
import Disclaimer from '../../\_disclaimer.mdx';

<Disclaimer />

Expand All @@ -16,11 +16,12 @@ The component uses its `data` and `dataPath` props to extract the necessary info
The BarcodeGenerator is typically used as follows:

1. Passing the credential object:

- The `data` prop receives the entire credential object generated by the previous step in the process.
- This prop is usually not specified directly in the component configuration, as it's automatically populated with the credential generate in the previous step.

2. Specifying the data path:
- Use the `dataPath` prop to specify a JSON pointer path to extract barcode data from the credential object.
- Use the `dataPath` prop to specify the AI codes and JSON pointer paths to extract the appropriate data for barcode generation.

## Example

Expand All @@ -29,7 +30,22 @@ The BarcodeGenerator is typically used as follows:
"name": "BarcodeGenerator",
"type": "Result",
"props": {
"dataPath": "/credentialSubject/outputEPCList/index/name"
"dataPath": {
"primary": {
"ai": "01",
"path": "/registeredId"
},
"qualifiers": [
{
"ai": "21",
"path": "/serialNumber"
},
{
"ai": "10",
"path": "/batchNumber"
}
]
}
}
}
```
Expand All @@ -38,15 +54,15 @@ This example specifies that for each item in the `outputEPCList`, the `name` fie

## Definitions

| Property | Required | Description | Type |
|----------|----------|-------------|------|
| name | Yes | The name of the component (should be "BarcodeGenerator")| String |
| type | Yes | The type of the component (should be "Result") | [ComponentType](/docs/mock-apps/common/component-type) |
| props | Yes | The properties for the BarcodeGenerator | [Props](/docs/mock-apps/components/barcode-generator#props) |
| Property | Required | Description | Type |
| -------- | -------- | -------------------------------------------------------- | ----------------------------------------------------------- |
| name | Yes | The name of the component (should be "BarcodeGenerator") | String |
| type | Yes | The type of the component (should be "Result") | [ComponentType](/docs/mock-apps/common/component-type) |
| props | Yes | The properties for the BarcodeGenerator | [Props](/docs/mock-apps/components/barcode-generator#props) |

### Props

| Property | Required | Description | Type |
|----------|----------|-------------|------|
| data | No | The credential object containing the data for barcode generation (usually automatically provided) | Object |
| dataPath | Yes | A JSON pointer path to extract barcode data from the credential object | String |
| Property | Required | Description | Type |
| -------- | -------- | ------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| data | No | The credential object containing the data for barcode generation (usually automatically provided) | Object |
| dataPath | Yes | A JSON pointer path to extract barcode data from the credential object | [AIData](/docs/mock-apps/common/construct-ai-data) |
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
"packages/*"
],
"scripts": {
"start": "cp app-config.json packages/mock-app/src/constants/app-config.json && cd packages/mock-app && yarn start",
"build": "yarn build:services && yarn build:components && yarn build:untp-test-suite",
"copy-config": "cp app-config.json packages/mock-app/src/constants/app-config.json && cp app-config.json packages/components/src/constants/app-config.json",
"start": "yarn copy-config && cd packages/mock-app && yarn start",
"build": "yarn copy-config && yarn build:services && yarn build:components && yarn build:untp-test-suite",
"build:services": "cd packages/services && yarn run build",
"build:components": "cd packages/components && yarn run build",
"build:untp-test-suite": "cd packages/untp-test-suite && yarn run build",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { allowedIndexKeys, extractFromElementString } from '@mock-app/services';
import { extractFromElementString, constructIdentifierData, constructElementString } from '@mock-app/services';
import { Box } from '@mui/material';
import JSONPointer from 'jsonpointer';
import { useEffect, useState } from 'react';
import Barcode from 'react-barcode';
import appConfig from '../../constants/app-config.json';
import { DataCarrierType } from '../../types/common.types';
import { toastMessage, Status } from '../ToastMessage/ToastMessage';

export interface IBarcodeProps {
data?: string[];
Expand All @@ -12,27 +14,33 @@ export const BarcodeGenerator = (props: IBarcodeProps) => {
const [values, setValues] = useState<string[]>([]);
useEffect(() => {
if (props.data && props.dataPath) {
const pathIndex = props.dataPath.split('/').findIndex((key) => allowedIndexKeys.includes(key));

if (pathIndex === -1) {
setValues([constructBarcode(JSONPointer.get(props.data, props.dataPath))]);
const aiData = constructIdentifierData(props.dataPath, props.data);
if (validateData(aiData)) {
const elementString = constructElementString(aiData);
setValues([constructBarcode(elementString)]);
} else {
const headPath = props.dataPath.split('/').slice(0, pathIndex).join('/');
const tailPath = props.dataPath
.split('/')
.slice(pathIndex + 1)
.join('/');
const array = JSONPointer.get(props.data, headPath);
const values = array.map((item: any) => JSONPointer.get(item, `/${tailPath}`));
const parsedValues = values.map((item: any) => {
return constructBarcode(item);
});

setValues(parsedValues);
toastMessage({ status: Status.warning, message: 'Invalid data for barcode generation' });
}
}
}, [props.data, props.dataPath]);

const validateData = (aiData: any) => {
if (!aiData) return false;
if (!aiData.primary || !aiData.primary.ai || !aiData.primary.value) return false;
const identifierSchemesForBarcode = (appConfig.identifierSchemes || []).filter(
(scheme) => scheme.carriers && scheme.carriers.includes(DataCarrierType.Barcode),
);
if (identifierSchemesForBarcode.length === 0) return false;

return identifierSchemesForBarcode.some((scheme) => {
const regex = new RegExp(scheme.format);
if (regex.test(aiData.primary.value)) {
return true;
}
return false;
});
};

const constructBarcode = (data: string) => {
const convertToGS1String = (obj: any) => {
if (typeof obj !== 'object' || obj === null) return '';
Expand Down Expand Up @@ -66,9 +74,9 @@ export const BarcodeGenerator = (props: IBarcodeProps) => {

return (
<Box display='flex' flexDirection='column' alignItems='center' justifyContent='space-evenly'>
{values.map((item) => {
{values.map((item, idx) => {
return (
<Box>
<Box key={idx}>
<Barcode value={item} />
</Box>
);
Expand Down
Loading

0 comments on commit c2d9322

Please sign in to comment.