kitchen-simulator 5.0.0-test.6 → 5.0.0-test.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -2
- package/src/components/toolbar/main/index.jsx +10 -70
- package/src/components/viewer3d/scene-creator.js +23 -26
- package/src/components/viewer3d/viewer3d.js +18 -18
- package/src/hooks/useCheckCart.js +0 -38
- package/src/hooks/useGetPricesBySku.js +0 -59
- package/src/hooks/useValidateToken.js +0 -181
- package/src/styles/export.js +0 -7
- package/src/styles/tabs.css +0 -40
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kitchen-simulator",
|
|
3
|
-
"version": "5.0.0-test.
|
|
3
|
+
"version": "5.0.0-test.7",
|
|
4
4
|
"description": "It is a kitchen simulator.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
|
|
@@ -16,7 +16,17 @@
|
|
|
16
16
|
},
|
|
17
17
|
|
|
18
18
|
"files": [
|
|
19
|
-
"src",
|
|
19
|
+
"src/*.js",
|
|
20
|
+
"src/*.jsx",
|
|
21
|
+
"src/catalog",
|
|
22
|
+
"src/components",
|
|
23
|
+
"src/utils",
|
|
24
|
+
"src/actions",
|
|
25
|
+
"src/reducers",
|
|
26
|
+
"src/class",
|
|
27
|
+
"src/plugins",
|
|
28
|
+
"src/shared-style",
|
|
29
|
+
"src/translator",
|
|
20
30
|
"README.md",
|
|
21
31
|
"LICENSE"
|
|
22
32
|
],
|
|
@@ -6,17 +6,16 @@ import { Map } from 'immutable';
|
|
|
6
6
|
import PropTypes from 'prop-types';
|
|
7
7
|
import React, { PureComponent } from 'react';
|
|
8
8
|
import { FaPlayCircle } from 'react-icons/fa';
|
|
9
|
-
import * as
|
|
10
|
-
import * as
|
|
11
|
-
import * as
|
|
12
|
-
import * as
|
|
13
|
-
import * as
|
|
14
|
-
import * as
|
|
15
|
-
import * as
|
|
16
|
-
import * as
|
|
17
|
-
import * as
|
|
18
|
-
import * as
|
|
19
|
-
import * as window_vertical from '../../../../demo/src/catalog/holes/window-vertical/planner-element';
|
|
9
|
+
import * as door_closet from '../../../catalog/holes/door-closet/planner-element';
|
|
10
|
+
import * as door_exterior from '../../../catalog/holes/door-exterior/planner-element';
|
|
11
|
+
import * as door_interior from '../../../catalog/holes/door-interior/planner-element';
|
|
12
|
+
import * as door_sliding from '../../../catalog/holes/door-sliding/planner-element';
|
|
13
|
+
import * as door_framed from '../../../catalog/holes/doorway-framed/planner-element';
|
|
14
|
+
import * as door_frameless from '../../../catalog/holes/doorway-frameless/planner-element';
|
|
15
|
+
import * as window_clear from '../../../catalog/holes/window-clear/planner-element';
|
|
16
|
+
import * as window_cross from '../../../catalog/holes/window-cross/planner-element';
|
|
17
|
+
import * as window_double_hung from '../../../catalog/holes/window-double-hung/planner-element';
|
|
18
|
+
import * as window_vertical from '../../../catalog/holes/window-vertical/planner-element';
|
|
20
19
|
import { formatNumber, toFixedFloat } from '../../../utils/math';
|
|
21
20
|
import FormNumberInput from '../../style/form-number-input';
|
|
22
21
|
import PlgItem from '../plugin-item.jsx';
|
|
@@ -3885,32 +3884,6 @@ export default class Toolbar extends PureComponent {
|
|
|
3885
3884
|
}
|
|
3886
3885
|
};
|
|
3887
3886
|
|
|
3888
|
-
let testData = [];
|
|
3889
|
-
if (process.env.MODE === 'staging') {
|
|
3890
|
-
for (let testJson in testJsonData) {
|
|
3891
|
-
testData.push(
|
|
3892
|
-
<S.testJsonItemWrapper
|
|
3893
|
-
onClick={() => {
|
|
3894
|
-
if (
|
|
3895
|
-
window.confirm(
|
|
3896
|
-
`Do you really load ${testJson}.json for KC test?`
|
|
3897
|
-
)
|
|
3898
|
-
) {
|
|
3899
|
-
this.context.projectActions.loadProject(
|
|
3900
|
-
JSON.parse(testJsonData[testJson].project_data),
|
|
3901
|
-
this.props.categoryData
|
|
3902
|
-
);
|
|
3903
|
-
this.setState({ addingJson: false });
|
|
3904
|
-
this.props.setToolbar('');
|
|
3905
|
-
}
|
|
3906
|
-
}}
|
|
3907
|
-
>
|
|
3908
|
-
{testJson}
|
|
3909
|
-
</S.testJsonItemWrapper>
|
|
3910
|
-
);
|
|
3911
|
-
}
|
|
3912
|
-
}
|
|
3913
|
-
|
|
3914
3887
|
const isShowMoldingMenuItem = (subCabinetCategory, item) => {
|
|
3915
3888
|
if (subCabinetCategory.name === TOE_KICK_MOLDING) {
|
|
3916
3889
|
const items = this.state.elements.items?.toArray() ?? [];
|
|
@@ -3997,25 +3970,6 @@ export default class Toolbar extends PureComponent {
|
|
|
3997
3970
|
);
|
|
3998
3971
|
})}
|
|
3999
3972
|
</S.SubCategoryItemWrapper>
|
|
4000
|
-
{process.env.MODE === 'staging' &&
|
|
4001
|
-
!!Object.keys(testJsonData).length && (
|
|
4002
|
-
<S.SubCategoryItemWrapper
|
|
4003
|
-
onClick={() =>
|
|
4004
|
-
this.setState({
|
|
4005
|
-
addingJson: !this.state.addingJson,
|
|
4006
|
-
selectedRoomElement: ''
|
|
4007
|
-
})
|
|
4008
|
-
}
|
|
4009
|
-
>
|
|
4010
|
-
<S.SubCategoryItem>
|
|
4011
|
-
<S.SubCategoryItemLabel
|
|
4012
|
-
style={{ marginLeft: 15, color: TEXT_COLOR_NEUTRAL_0 }}
|
|
4013
|
-
>
|
|
4014
|
-
Test JSONs
|
|
4015
|
-
</S.SubCategoryItemLabel>
|
|
4016
|
-
</S.SubCategoryItem>
|
|
4017
|
-
</S.SubCategoryItemWrapper>
|
|
4018
|
-
)}
|
|
4019
3973
|
</S.SubToolbarWrapper>
|
|
4020
3974
|
{selectedRoomElement && (
|
|
4021
3975
|
<S.SubToolbarWrapper
|
|
@@ -4065,20 +4019,6 @@ export default class Toolbar extends PureComponent {
|
|
|
4065
4019
|
})}
|
|
4066
4020
|
</S.SubToolbarWrapper>
|
|
4067
4021
|
)}
|
|
4068
|
-
{process.env.MODE === 'staging' &&
|
|
4069
|
-
!!Object.keys(testJsonData).length &&
|
|
4070
|
-
this.state.addingJson && (
|
|
4071
|
-
<S.SubToolbarWrapper
|
|
4072
|
-
id="test_json_datas"
|
|
4073
|
-
style={{
|
|
4074
|
-
alignItems: 'flex-start',
|
|
4075
|
-
marginLeft: 20,
|
|
4076
|
-
minWidth: 250
|
|
4077
|
-
}}
|
|
4078
|
-
>
|
|
4079
|
-
{testData}
|
|
4080
|
-
</S.SubToolbarWrapper>
|
|
4081
|
-
)}
|
|
4082
4022
|
</div>
|
|
4083
4023
|
)
|
|
4084
4024
|
},
|
|
@@ -1,49 +1,46 @@
|
|
|
1
1
|
import * as Three from 'three';
|
|
2
|
+
import { Color, Group } from 'three';
|
|
2
3
|
import createGrid from './grid-creator';
|
|
3
4
|
import { disposeObject } from './three-memory-cleaner';
|
|
4
|
-
import { Color, Group } from 'three';
|
|
5
|
-
import { isUndefined } from 'util';
|
|
6
5
|
import {
|
|
7
|
-
MODE_DRAWING_ITEM_3D,
|
|
8
|
-
EPSILON,
|
|
9
|
-
DISTANCE_EPSILON,
|
|
10
|
-
OBJTYPE_MESH,
|
|
11
|
-
ARROW_TEXT_FORECOLOR,
|
|
12
|
-
ARROW_TEXT_BACKCOLOR,
|
|
13
|
-
ARROW_TEXT_FONTFACE,
|
|
14
|
-
UNIT_CENTIMETER,
|
|
15
|
-
SHADE_DARK_PURPLE_COLOR,
|
|
16
|
-
MODE_DRAGGING_ITEM_3D,
|
|
17
|
-
MODE_ROTATING_ITEM_3D,
|
|
18
6
|
ANIMATE_STEP_MAX,
|
|
19
7
|
ANIMATE_STEP_MIN,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
8
|
+
ARRAY_3D_MODES,
|
|
9
|
+
ARROW_TEXT_BACKCOLOR,
|
|
10
|
+
ARROW_TEXT_FONTFACE,
|
|
11
|
+
ARROW_TEXT_FORECOLOR,
|
|
24
12
|
BASE_CABINET_LAYOUTPOS,
|
|
25
|
-
|
|
26
|
-
WALL_CABINET_LAYOUTPOS,
|
|
13
|
+
BOTTOM_MOLDING_LOCATION,
|
|
27
14
|
DECIMAL_PLACES_2,
|
|
28
15
|
DIFFERENT_VALUES_PATH_LENGTH,
|
|
16
|
+
DISTANCE_EPSILON,
|
|
17
|
+
EPSILON,
|
|
18
|
+
MIDDLE_MOLDING_LOCATION,
|
|
19
|
+
MODE_DRAGGING_ITEM_3D,
|
|
20
|
+
MODE_DRAWING_ITEM_3D,
|
|
21
|
+
MODE_IDLE,
|
|
29
22
|
MODE_IDLE_3D,
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
MODE_ROTATING_ITEM_3D,
|
|
24
|
+
OBJTYPE_MESH,
|
|
25
|
+
SHADE_DARK_PURPLE_COLOR,
|
|
26
|
+
TOP_MOLDING_LOCATION,
|
|
27
|
+
UNIT_CENTIMETER,
|
|
28
|
+
WALL_CABINET_LAYOUTPOS
|
|
32
29
|
} from '../../constants';
|
|
33
|
-
import {
|
|
30
|
+
import { GeometryUtils, IDBroker, MoldingUtils } from '../../utils/export';
|
|
34
31
|
import convert from 'convert-units';
|
|
35
32
|
import { verticesDistance } from '../../utils/geometry';
|
|
36
|
-
import * as GeomUtils from '../../../demo/src/catalog/utils/geom-utils';
|
|
37
|
-
import { loadTexture } from '../../../demo/src/catalog/utils/item-loader';
|
|
38
33
|
import { returnReplaceableDeepSearchType } from '../viewer2d/utils';
|
|
39
34
|
import {
|
|
40
|
-
|
|
35
|
+
animateDoor,
|
|
41
36
|
isElevationView,
|
|
42
37
|
isEmpty,
|
|
43
|
-
|
|
38
|
+
replaceMeshesWithLineSegments,
|
|
44
39
|
translateDrawer
|
|
45
40
|
} from '../../../src/utils/helper';
|
|
46
41
|
import { formatNumber } from '../../utils/math';
|
|
42
|
+
import * as GeomUtils from '../../../src/catalog/utils/geom-utils.js';
|
|
43
|
+
import { loadTexture } from '../../../src/catalog/utils/item-loader.jsx';
|
|
47
44
|
|
|
48
45
|
let transformBox;
|
|
49
46
|
export var fVLine = [];
|
|
@@ -5,32 +5,31 @@ import PropTypes from 'prop-types';
|
|
|
5
5
|
import ReactDOM from 'react-dom';
|
|
6
6
|
import * as Three from 'three';
|
|
7
7
|
import {
|
|
8
|
+
checkCabinetOverlap,
|
|
9
|
+
createBacksplash,
|
|
10
|
+
deleteSpecifiedMeshObjects,
|
|
11
|
+
fVLine,
|
|
12
|
+
getDistances,
|
|
8
13
|
parseData,
|
|
9
14
|
updateScene,
|
|
10
|
-
visibleTransformBox
|
|
11
|
-
getDistances,
|
|
12
|
-
fVLine,
|
|
13
|
-
deleteSpecifiedMeshObjects,
|
|
14
|
-
createBacksplash,
|
|
15
|
-
checkCabinetOverlap
|
|
15
|
+
visibleTransformBox
|
|
16
16
|
} from './scene-creator';
|
|
17
|
-
import { disposeScene } from './three-memory-cleaner';
|
|
18
|
-
import { disposeObject } from './three-memory-cleaner';
|
|
17
|
+
import { disposeObject, disposeScene } from './three-memory-cleaner';
|
|
19
18
|
import diff from 'immutablediff';
|
|
20
19
|
import * as SharedStyle from '../../shared-style';
|
|
21
20
|
import {
|
|
22
|
-
|
|
23
|
-
MODE_IDLE_3D,
|
|
21
|
+
BASE_CABINET_LAYOUTPOS,
|
|
24
22
|
MODE_3D_VIEW,
|
|
25
|
-
|
|
23
|
+
MODE_DRAGGING_ITEM_3D,
|
|
26
24
|
MODE_DRAWING_HOLE_3D,
|
|
27
|
-
|
|
25
|
+
MODE_DRAWING_ITEM_3D,
|
|
28
26
|
MODE_ELEVATION_VIEW,
|
|
29
|
-
|
|
27
|
+
MODE_IDLE_3D,
|
|
30
28
|
MODE_ROTATING_ITEM_3D,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
SECONDARY_PURPLE_COLOR,
|
|
30
|
+
TALL_CABINET_LAYOUTPOS,
|
|
31
|
+
UNIT_CENTIMETER,
|
|
32
|
+
WALL_CABINET_LAYOUTPOS
|
|
34
33
|
} from '../../constants';
|
|
35
34
|
|
|
36
35
|
import { isUndefined } from 'util';
|
|
@@ -40,13 +39,14 @@ import { GeometryUtils } from '../../utils/export';
|
|
|
40
39
|
import { handleCamRect, isElevationView, isEmpty } from '../../utils/helper';
|
|
41
40
|
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
|
|
42
41
|
import CameraControls from 'camera-controls';
|
|
43
|
-
CameraControls.install({ THREE: Three });
|
|
44
42
|
import { returnReplaceableDeepSearchType } from '../viewer2d/utils';
|
|
45
43
|
import {
|
|
46
44
|
getAllMeshes,
|
|
47
45
|
vectorIntersectWithMesh
|
|
48
46
|
} from '../../utils/objects-utils';
|
|
49
47
|
|
|
48
|
+
CameraControls.install({ THREE: Three });
|
|
49
|
+
|
|
50
50
|
export default class Scene3DViewer extends React.Component {
|
|
51
51
|
constructor(props) {
|
|
52
52
|
super(props);
|
|
@@ -2978,7 +2978,7 @@ export default class Scene3DViewer extends React.Component {
|
|
|
2978
2978
|
line = line.children[0].children[0];
|
|
2979
2979
|
// index(faces) of the line
|
|
2980
2980
|
const indexAttribute = line.geometry.getIndex();
|
|
2981
|
-
|
|
2981
|
+
let firstFaceIndices = undefined;
|
|
2982
2982
|
if (indexAttribute && indexAttribute.length > 0) {
|
|
2983
2983
|
firstFaceIndices = [
|
|
2984
2984
|
indexAttribute.getX(0),
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import { useQuery } from 'react-query';
|
|
3
|
-
import ls from 'localstorage-slim';
|
|
4
|
-
import { LOCAL_STORAGE_TOKEN_VALUE } from '../../src/constants';
|
|
5
|
-
|
|
6
|
-
const fetchCart = async () => {
|
|
7
|
-
const accessToken = ls.get(LOCAL_STORAGE_TOKEN_VALUE);
|
|
8
|
-
const visualizerName = sessionStorage.getItem('visualizerName');
|
|
9
|
-
|
|
10
|
-
const response = await axios.post(
|
|
11
|
-
`${process.env.API_URL}/api/project/checkCart`,
|
|
12
|
-
{
|
|
13
|
-
client_name: visualizerName,
|
|
14
|
-
user_token: accessToken
|
|
15
|
-
}
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
return response.data;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const useCheckCart = ({ enabled = true }) =>
|
|
22
|
-
useQuery({
|
|
23
|
-
queryKey: ['cart'],
|
|
24
|
-
queryFn: fetchCart,
|
|
25
|
-
initialData: {
|
|
26
|
-
is_empty: true
|
|
27
|
-
},
|
|
28
|
-
enabled,
|
|
29
|
-
retry: 1,
|
|
30
|
-
refetchOnWindowFocus: false,
|
|
31
|
-
refetchOnWindowBlur: false,
|
|
32
|
-
onSuccess: data => {
|
|
33
|
-
console.log(`[useCheckCart] Fetched cart check data`, data);
|
|
34
|
-
},
|
|
35
|
-
onError: error => {
|
|
36
|
-
console.log(`[useCheckCart] Failed to fetch cart check`, error);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import { useQuery } from 'react-query';
|
|
3
|
-
import ls from 'localstorage-slim';
|
|
4
|
-
import {
|
|
5
|
-
LOCAL_STORAGE_TOKEN_VALUE,
|
|
6
|
-
LOCAL_STORAGE_CUSTOMER_INFO
|
|
7
|
-
} from '../../src/constants';
|
|
8
|
-
|
|
9
|
-
function formatPrice(value) {
|
|
10
|
-
const num = parseFloat((value || '').replace(/,/g, ''));
|
|
11
|
-
return isNaN(num) ? 0 : parseFloat(num.toFixed(2));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const fetchPricesBySku = async (ids, accessToken) => {
|
|
15
|
-
const customer = ls.get(LOCAL_STORAGE_CUSTOMER_INFO);
|
|
16
|
-
|
|
17
|
-
const visualizerName = sessionStorage.getItem('visualizerName');
|
|
18
|
-
|
|
19
|
-
const response = await axios.post(
|
|
20
|
-
`${process.env.API_URL}/api/pricing/getPrices`,
|
|
21
|
-
{
|
|
22
|
-
client_name: visualizerName,
|
|
23
|
-
customer_email: customer?.email || '',
|
|
24
|
-
skus: ids,
|
|
25
|
-
token: accessToken
|
|
26
|
-
}
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
discount_type: response.data.discount_type || '',
|
|
31
|
-
prices: response.data.prices.map(priceProduct => ({
|
|
32
|
-
...priceProduct,
|
|
33
|
-
sku: priceProduct.internal_sku,
|
|
34
|
-
regular_price: formatPrice(priceProduct.price),
|
|
35
|
-
discounted_price: formatPrice(priceProduct.discounted_price)
|
|
36
|
-
}))
|
|
37
|
-
};
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export const useGetPricesBySku = ids => {
|
|
41
|
-
const accessToken = ls.get(LOCAL_STORAGE_TOKEN_VALUE);
|
|
42
|
-
|
|
43
|
-
return useQuery({
|
|
44
|
-
queryKey: ['prices', ids, accessToken],
|
|
45
|
-
queryFn: () => fetchPricesBySku(ids, accessToken),
|
|
46
|
-
enabled: Array.isArray(ids) && ids.length > 0,
|
|
47
|
-
initialData: {
|
|
48
|
-
discount_type: '',
|
|
49
|
-
prices: []
|
|
50
|
-
},
|
|
51
|
-
retry: 1,
|
|
52
|
-
onSuccess: data => {
|
|
53
|
-
ls.set('DISCOUNT_TYPE', data.discount_type);
|
|
54
|
-
},
|
|
55
|
-
onError: error => {
|
|
56
|
-
console.log(`[useGetPricesBySku] Failed to fetch prices`, error);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
};
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
// hooks/useValidateToken.js
|
|
2
|
-
import axios from 'axios';
|
|
3
|
-
import { useQuery } from 'react-query';
|
|
4
|
-
import ls from 'localstorage-slim';
|
|
5
|
-
import {
|
|
6
|
-
LOCAL_STORAGE_TOKEN_VALUE,
|
|
7
|
-
LOCAL_STORAGE_CUSTOMER_INFO,
|
|
8
|
-
LOCAL_STORAGE_ORIGINAL_TOKEN
|
|
9
|
-
} from '../../src/constants';
|
|
10
|
-
import {
|
|
11
|
-
ENCODED_QUERY_PARAM_TOKEN,
|
|
12
|
-
QUERY_PARAM_TOKEN
|
|
13
|
-
} from '../../demo/src/CrossSignOn';
|
|
14
|
-
|
|
15
|
-
const LOG_PREFIX = `[Cross Sign On]`;
|
|
16
|
-
|
|
17
|
-
function persistAccessToken(accessToken) {
|
|
18
|
-
const url = new URL(window.location.href);
|
|
19
|
-
const token = url.searchParams.get(QUERY_PARAM_TOKEN);
|
|
20
|
-
const encodedToken = url.searchParams.get(ENCODED_QUERY_PARAM_TOKEN);
|
|
21
|
-
|
|
22
|
-
if (!accessToken) return;
|
|
23
|
-
|
|
24
|
-
if (!token && !encodedToken) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (token) {
|
|
29
|
-
url.searchParams.set(QUERY_PARAM_TOKEN, accessToken);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (encodedToken) {
|
|
33
|
-
url.searchParams.set(ENCODED_QUERY_PARAM_TOKEN, accessToken);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
console.log(`${LOG_PREFIX} Persisting access token`);
|
|
37
|
-
ls.set(LOCAL_STORAGE_TOKEN_VALUE, accessToken);
|
|
38
|
-
|
|
39
|
-
if (window.location.href !== url.toString()) {
|
|
40
|
-
window.history.replaceState({}, document.title, url.toString());
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function persistCustomerInfo(customerInfo) {
|
|
45
|
-
if (!customerInfo) return;
|
|
46
|
-
|
|
47
|
-
console.log(`${LOG_PREFIX} Persisting customer info`);
|
|
48
|
-
ls.set(LOCAL_STORAGE_CUSTOMER_INFO, customerInfo);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async function refreshToken(currentToken) {
|
|
52
|
-
const visualizerName = sessionStorage.getItem('visualizerName');
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
const { data: refreshData } = await axios.post(
|
|
56
|
-
`${process.env.API_URL}/api/token/refresh`,
|
|
57
|
-
{
|
|
58
|
-
client_name: visualizerName,
|
|
59
|
-
token: currentToken
|
|
60
|
-
}
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
if (
|
|
64
|
-
refreshData &&
|
|
65
|
-
refreshData.status === 'success' &&
|
|
66
|
-
refreshData.accessToken
|
|
67
|
-
) {
|
|
68
|
-
return {
|
|
69
|
-
refreshed: true,
|
|
70
|
-
token: refreshData.accessToken,
|
|
71
|
-
raw: refreshData
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
console.error(`${LOG_PREFIX} Token refresh failed`, refreshData?.message);
|
|
76
|
-
throw new Error(refreshData?.message || 'Token refresh failed');
|
|
77
|
-
} catch (err) {
|
|
78
|
-
console.error(`${LOG_PREFIX} Error refreshing token`, err);
|
|
79
|
-
throw err;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Normalizes validate/refresh results so consumers have a predictable shape.
|
|
85
|
-
* Returns:
|
|
86
|
-
* {
|
|
87
|
-
* token: string | null,
|
|
88
|
-
* customer: { email, firstName, lastName, tier } | null,
|
|
89
|
-
* source: 'validated' | 'refreshed' | 'object' | 'unknown' | 'none'
|
|
90
|
-
* }
|
|
91
|
-
*/
|
|
92
|
-
async function fetchValidateToken(accessToken) {
|
|
93
|
-
const visualizerName = sessionStorage.getItem('visualizerName');
|
|
94
|
-
// Case: string token flow
|
|
95
|
-
if (typeof accessToken === 'string' && accessToken) {
|
|
96
|
-
try {
|
|
97
|
-
const { data } = await axios.post(
|
|
98
|
-
`${process.env.API_URL}/api/token/validate`,
|
|
99
|
-
{
|
|
100
|
-
client_name: visualizerName,
|
|
101
|
-
token: accessToken
|
|
102
|
-
}
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
if (data && data.status !== 'error' && data.email) {
|
|
106
|
-
const customer = {
|
|
107
|
-
email: data.email,
|
|
108
|
-
firstName: data.firstName,
|
|
109
|
-
lastName: data.lastName,
|
|
110
|
-
tier: data.tier
|
|
111
|
-
};
|
|
112
|
-
ls.set(LOCAL_STORAGE_ORIGINAL_TOKEN, accessToken);
|
|
113
|
-
persistAccessToken(accessToken);
|
|
114
|
-
persistCustomerInfo(customer);
|
|
115
|
-
|
|
116
|
-
return {
|
|
117
|
-
token: accessToken,
|
|
118
|
-
customer,
|
|
119
|
-
source: 'validated'
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// If API returns an error status, try refresh
|
|
124
|
-
if (
|
|
125
|
-
data?.status === 'error' &&
|
|
126
|
-
data.message.toLowerCase().includes('expired')
|
|
127
|
-
) {
|
|
128
|
-
console.log(`${LOG_PREFIX} Token validation failed`, data.message);
|
|
129
|
-
const refreshed = await refreshToken(accessToken);
|
|
130
|
-
|
|
131
|
-
if (refreshed.token && typeof refreshed.token === 'string') {
|
|
132
|
-
ls.set(LOCAL_STORAGE_ORIGINAL_TOKEN, refreshed.token);
|
|
133
|
-
persistAccessToken(refreshed.token);
|
|
134
|
-
|
|
135
|
-
window.dispatchEvent(
|
|
136
|
-
new CustomEvent('token-changed', { detail: refreshed.token })
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
token: refreshed.token,
|
|
142
|
-
customer: null, // customer not returned by refresh; will be filled by next authenticated fetch
|
|
143
|
-
source: 'refreshed'
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// If no email but not an explicit error, just return token
|
|
148
|
-
return {
|
|
149
|
-
token: accessToken,
|
|
150
|
-
customer: null,
|
|
151
|
-
source: 'validated'
|
|
152
|
-
};
|
|
153
|
-
} catch (e) {
|
|
154
|
-
console.log(`${LOG_PREFIX} Failed fetching customer info`, e);
|
|
155
|
-
const refreshed = await refreshToken(accessToken);
|
|
156
|
-
return {
|
|
157
|
-
token: refreshed.token ? refreshed.token : accessToken,
|
|
158
|
-
customer: null,
|
|
159
|
-
source: 'refreshed'
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// No token
|
|
165
|
-
return { token: null, customer: null, source: 'unknown' };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export const useValidateToken = accessToken => {
|
|
169
|
-
return useQuery({
|
|
170
|
-
queryKey: [
|
|
171
|
-
'validate-token',
|
|
172
|
-
typeof accessToken === 'object' ? accessToken?.token : accessToken
|
|
173
|
-
],
|
|
174
|
-
queryFn: () => fetchValidateToken(accessToken),
|
|
175
|
-
retry: 1,
|
|
176
|
-
onError: error => {
|
|
177
|
-
console.error(`[useValidateToken] Validation failed`, error);
|
|
178
|
-
},
|
|
179
|
-
initialData: { token: null, customer: null, source: 'none' }
|
|
180
|
-
});
|
|
181
|
-
};
|
package/src/styles/export.js
DELETED
package/src/styles/tabs.css
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
.react-tabs__tab-list {
|
|
2
|
-
border-bottom: 1px solid #aaa;
|
|
3
|
-
margin: 0 0 10px;
|
|
4
|
-
padding: 0;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
.react-tabs__tab {
|
|
8
|
-
display: inline-block;
|
|
9
|
-
border: 1px solid transparent;
|
|
10
|
-
border-bottom: none;
|
|
11
|
-
bottom: -1px;
|
|
12
|
-
position: relative;
|
|
13
|
-
list-style: none;
|
|
14
|
-
padding: 6px 12px;
|
|
15
|
-
cursor: pointer;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.react-tabs__tab--selected,
|
|
19
|
-
.react-tabs__tab:focus {
|
|
20
|
-
border-color: #aaa;
|
|
21
|
-
color: #1ca6fc;
|
|
22
|
-
outline: none;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.react-tabs__tab-panel {
|
|
26
|
-
display: none;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.react-tabs__tab-panel--selected {
|
|
30
|
-
display: block;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
@keyframes spin {
|
|
34
|
-
from {
|
|
35
|
-
transform: rotate(0deg);
|
|
36
|
-
}
|
|
37
|
-
to {
|
|
38
|
-
transform: rotate(360deg);
|
|
39
|
-
}
|
|
40
|
-
}
|