@yogiswara/honcho-editor-ui 2.10.14 → 2.10.16

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.
@@ -28,10 +28,10 @@ interface Props {
28
28
  contrastScore: number;
29
29
  clarityScore: number;
30
30
  sharpnessScore: number;
31
- onTempChange: (field: keyof AdjustmentState, value: number) => void;
32
- onTintChange: (field: keyof AdjustmentState, value: number) => void;
33
- onVibranceChange: (field: keyof AdjustmentState, value: number) => void;
34
- onSaturationChange: (field: keyof AdjustmentState, value: number) => void;
31
+ setTempScore: (field: keyof AdjustmentState, value: number) => void;
32
+ setTintScore: (field: keyof AdjustmentState, value: number) => void;
33
+ setVibranceScore: (field: keyof AdjustmentState, value: number) => void;
34
+ setSaturationScore: (field: keyof AdjustmentState, value: number) => void;
35
35
  onExposureChange: (field: keyof AdjustmentState, value: number) => void;
36
36
  onHighlightsChange: (field: keyof AdjustmentState, value: number) => void;
37
37
  onShadowsChange: (field: keyof AdjustmentState, value: number) => void;
@@ -31,7 +31,7 @@ export default function HImageEditorMobile(props) {
31
31
  const renderPanelContent = () => {
32
32
  switch (props.activePanel) {
33
33
  case 'colorAdjustment':
34
- return _jsx(HTabColorAdjustmentMobile, { activeSubPanel: props.activeSubPanel, innerRef: props.innerRef, onDragStart: props.onDragStart, onDragEnd: props.onDragEnd, onExposureChange: props.onExposureChange, onContrastChange: props.onContrastChange, onHighlightsChange: props.onHighlightsChange, onShadowsChange: props.onShadowsChange, onWhitesChange: props.onWhitesChange, onBlacksChange: props.onBlacksChange, onTempChange: props.onTempChange, onTintChange: props.onTintChange, onVibranceChange: props.onVibranceChange, onSaturationChange: props.onSaturationChange, exposureScore: props.exposureScore, contrastScore: props.contrastScore, highlightsScore: props.highlightsScore, shadowScore: props.shadowScore, whiteScore: props.whiteScore, blackScore: props.blackScore, tempScore: props.tempScore, tintScore: props.tintScore, vibranceScore: props.vibranceScore, saturationScore: props.saturationScore, isBatchMode: props.isBatchMode, sharpnessScore: props.sharpnessScore, onSharpnessChange: props.onSharpnessChange, clarityScore: props.clarityScore, onClarityChange: props.onClarityChange });
34
+ return _jsx(HTabColorAdjustmentMobile, { activeSubPanel: props.activeSubPanel, innerRef: props.innerRef, onDragStart: props.onDragStart, onDragEnd: props.onDragEnd, onExposureChange: props.onExposureChange, onContrastChange: props.onContrastChange, onHighlightsChange: props.onHighlightsChange, onShadowsChange: props.onShadowsChange, onWhitesChange: props.onWhitesChange, onBlacksChange: props.onBlacksChange, setTempScore: props.setTempScore, setTintScore: props.setTintScore, setVibranceScore: props.setVibranceScore, setSaturationScore: props.setSaturationScore, exposureScore: props.exposureScore, contrastScore: props.contrastScore, highlightsScore: props.highlightsScore, shadowScore: props.shadowScore, whiteScore: props.whiteScore, blackScore: props.blackScore, tempScore: props.tempScore, tintScore: props.tintScore, vibranceScore: props.vibranceScore, saturationScore: props.saturationScore, isBatchMode: props.isBatchMode, sharpnessScore: props.sharpnessScore, onSharpnessChange: props.onSharpnessChange, clarityScore: props.clarityScore, onClarityChange: props.onClarityChange });
35
35
  case 'preset':
36
36
  return _jsx(HTabPresetMobile, { ...props });
37
37
  default:
@@ -5,10 +5,10 @@ interface Props {
5
5
  saturationScore: number;
6
6
  vibranceScore: number;
7
7
  isBatchMode: boolean;
8
- onTempChange: (field: keyof AdjustmentState, value: number) => void;
9
- onTintChange: (field: keyof AdjustmentState, value: number) => void;
10
- onVibranceChange: (field: keyof AdjustmentState, value: number) => void;
11
- onSaturationChange: (field: keyof AdjustmentState, value: number) => void;
8
+ setTempScore: (field: keyof AdjustmentState, value: number) => void;
9
+ setTintScore: (field: keyof AdjustmentState, value: number) => void;
10
+ setVibranceScore: (field: keyof AdjustmentState, value: number) => void;
11
+ setSaturationScore: (field: keyof AdjustmentState, value: number) => void;
12
12
  onDragStart: () => void;
13
13
  onDragEnd: () => void;
14
14
  }
@@ -1,8 +1,79 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
2
3
  import { Stack, Slider, Typography } from "@mui/material";
3
4
  import useHonchoTypography from "../../themes/honchoTheme";
4
5
  import useColors from '../../themes/colors';
5
6
  import useSliderEvents from "../editor/sliderComponents/useSliderEvents";
7
+ const formatValue = (value) => {
8
+ if (value > 0)
9
+ return `+${value}`;
10
+ if (value < 0)
11
+ return value.toString();
12
+ return "0";
13
+ };
14
+ function useAdjustmentField(propValue, setValue, onDragStart, onDragEnd, isBatchMode) {
15
+ const [local, setLocal] = useState(formatValue(propValue));
16
+ const [started, setStarted] = useState(false);
17
+ // keep sync with external changes
18
+ useEffect(() => {
19
+ setLocal(formatValue(propValue));
20
+ }, [propValue]);
21
+ const handleChange = (e, min, max) => {
22
+ const raw = e.target.value;
23
+ setLocal(raw);
24
+ if (raw === "" || raw === "+" || raw === "-")
25
+ return;
26
+ let num = parseInt(raw, 10);
27
+ if (isNaN(num))
28
+ return;
29
+ num = Math.max(min, Math.min(max, num));
30
+ // start batch on first valid change
31
+ if (!started && !isBatchMode) {
32
+ onDragStart();
33
+ setStarted(true);
34
+ }
35
+ setValue(num);
36
+ };
37
+ const handleDoubleClick = () => {
38
+ if (!isBatchMode) {
39
+ onDragStart();
40
+ }
41
+ setLocal("0");
42
+ setValue(0);
43
+ if (!isBatchMode) {
44
+ onDragEnd();
45
+ }
46
+ };
47
+ const handleBlur = (min, max) => {
48
+ if (local === "" || local === "+" || local === "-") {
49
+ setLocal("0");
50
+ setValue(0);
51
+ }
52
+ else {
53
+ let num = parseInt(local, 10);
54
+ if (isNaN(num))
55
+ num = 0;
56
+ num = Math.max(min, Math.min(max, num));
57
+ setLocal(formatValue(num));
58
+ setValue(num);
59
+ }
60
+ // end batch when user leaves field
61
+ if (started) {
62
+ onDragEnd();
63
+ setStarted(false);
64
+ }
65
+ };
66
+ const handleKeyDown = (e) => {
67
+ if (e.key === "Enter") {
68
+ e.target.blur(); // blur the actual input
69
+ if (started) {
70
+ onDragEnd();
71
+ setStarted(false);
72
+ }
73
+ }
74
+ };
75
+ return { local, handleChange, handleBlur, handleKeyDown, handleDoubleClick };
76
+ }
6
77
  export default function HSliderColorMobile(props) {
7
78
  const typography = useHonchoTypography();
8
79
  const colors = useColors();
@@ -10,6 +81,10 @@ export default function HSliderColorMobile(props) {
10
81
  const tintSliderRef = useSliderEvents(props.onDragStart, props.onDragEnd, props.isBatchMode);
11
82
  const vibranceSliderRef = useSliderEvents(props.onDragStart, props.onDragEnd, props.isBatchMode);
12
83
  const saturationSliderRef = useSliderEvents(props.onDragStart, props.onDragEnd, props.isBatchMode);
84
+ const tempInput = useAdjustmentField(props.tempScore, (val) => props.setTempScore("tempScore", val), props.onDragStart, props.onDragEnd, props.isBatchMode);
85
+ const tintInput = useAdjustmentField(props.tintScore, (val) => props.setTintScore("tintScore", val), props.onDragStart, props.onDragEnd, props.isBatchMode);
86
+ const vibranceInput = useAdjustmentField(props.vibranceScore, (val) => props.setVibranceScore("vibranceScore", val), props.onDragStart, props.onDragEnd, props.isBatchMode);
87
+ const saturationInput = useAdjustmentField(props.saturationScore, (val) => props.setSaturationScore("saturationScore", val), props.onDragStart, props.onDragEnd, props.isBatchMode);
13
88
  const blueScale = '#292bc0'; // Blue color on left
14
89
  const yellowScale = '#dfdc28'; // Yellow color on right
15
90
  const greenScale = '#00ff04';
@@ -47,7 +122,7 @@ export default function HSliderColorMobile(props) {
47
122
  const clampedValue = Math.max(min, Math.min(max, numericValue));
48
123
  onChange(clampedValue);
49
124
  };
50
- return (_jsx(_Fragment, { children: _jsxs(Stack, { spacing: 0, direction: "column", sx: { width: '100%', paddingX: 1, m: "0px" }, children: [_jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { pt: '10px', pb: '0px', '&:focus-within .MuiFilledInput-input': focusedInputStyle }, children: [_jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, onDoubleClick: () => props.onTempChange("tempScore", 0), children: "Temperature" }), _jsx(Typography, { sx: {
125
+ return (_jsx(_Fragment, { children: _jsxs(Stack, { spacing: 0, direction: "column", sx: { width: '100%', paddingX: 1, m: "0px" }, children: [_jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { pt: '10px', pb: '0px', '&:focus-within .MuiFilledInput-input': focusedInputStyle }, children: [_jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, onDoubleClick: tempInput.handleDoubleClick, children: "Temperature" }), _jsx(Typography, { sx: {
51
126
  ...typography.bodyMedium, // Use your standard typography
52
127
  color: colors.surface,
53
128
  width: "40px", // Keep the fixed width for alignment
@@ -69,7 +144,7 @@ export default function HSliderColorMobile(props) {
69
144
  boxShadow: 'none',
70
145
  pointerEvents: 'auto', // IMPORTANT: Re-enable interaction ONLY for the thumb
71
146
  }
72
- }, size: "small", value: props.tempScore, step: 1, min: -100, max: 100, onChange: (_event, newValue) => props.onTempChange("tempScore", newValue), onDoubleClick: () => props.onTempChange("tempScore", 0) }), _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { pt: '10px', pb: '0px', '&:focus-within .MuiFilledInput-input': focusedInputStyle }, children: [_jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, onDoubleClick: () => props.onTintChange("tintScore", 0), children: "Tint" }), _jsx(Typography, { sx: {
147
+ }, size: "small", value: props.tempScore, step: 1, min: -100, max: 100, onChange: (_event, newValue) => props.setTempScore("tempScore", newValue), onDoubleClick: tempInput.handleDoubleClick }), _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { pt: '10px', pb: '0px', '&:focus-within .MuiFilledInput-input': focusedInputStyle }, children: [_jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, onDoubleClick: tintInput.handleDoubleClick, children: "Tint" }), _jsx(Typography, { sx: {
73
148
  ...typography.bodyMedium, // Use your standard typography
74
149
  color: colors.surface,
75
150
  width: "40px", // Keep the fixed width for alignment
@@ -91,7 +166,7 @@ export default function HSliderColorMobile(props) {
91
166
  boxShadow: 'none',
92
167
  pointerEvents: 'auto',
93
168
  }
94
- }, size: "small", value: props.tintScore, step: 1, min: -100, max: 100, onChange: (_event, newValue) => props.onTintChange("tintScore", newValue), onDoubleClick: () => props.onTintChange("tintScore", 0) }), _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { pt: '10px', pb: '0px', '&:focus-within .MuiFilledInput-input': focusedInputStyle }, children: [_jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, onDoubleClick: () => props.onVibranceChange("vibranceScore", 0), children: "Vibrance" }), _jsx(Typography, { sx: {
169
+ }, size: "small", value: props.tintScore, step: 1, min: -100, max: 100, onChange: (_event, newValue) => props.setTintScore("tintScore", newValue), onDoubleClick: tintInput.handleDoubleClick }), _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { pt: '10px', pb: '0px', '&:focus-within .MuiFilledInput-input': focusedInputStyle }, children: [_jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, onDoubleClick: vibranceInput.handleDoubleClick, children: "Vibrance" }), _jsx(Typography, { sx: {
95
170
  ...typography.bodyMedium, // Use your standard typography
96
171
  color: colors.surface,
97
172
  width: "40px", // Keep the fixed width for alignment
@@ -113,7 +188,7 @@ export default function HSliderColorMobile(props) {
113
188
  boxShadow: 'none',
114
189
  pointerEvents: 'auto',
115
190
  }
116
- }, size: "small", value: props.vibranceScore, step: 1, min: -100, max: 100, onChange: (_event, newValue) => props.onVibranceChange("vibranceScore", newValue), onDoubleClick: () => props.onVibranceChange("vibranceScore", 0) }), _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { pt: '10px', pb: '0px', '&:focus-within .MuiFilledInput-input': focusedInputStyle }, children: [_jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, onDoubleClick: () => props.onSaturationChange("saturationScore", 0), children: "Saturation" }), _jsx(Typography, { sx: {
191
+ }, size: "small", value: props.vibranceScore, step: 1, min: -100, max: 100, onChange: (_event, newValue) => props.setVibranceScore("vibranceScore", newValue), onDoubleClick: vibranceInput.handleDoubleClick }), _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { pt: '10px', pb: '0px', '&:focus-within .MuiFilledInput-input': focusedInputStyle }, children: [_jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, onDoubleClick: saturationInput.handleDoubleClick, children: "Saturation" }), _jsx(Typography, { sx: {
117
192
  ...typography.bodyMedium, // Use your standard typography
118
193
  color: colors.surface,
119
194
  width: "40px", // Keep the fixed width for alignment
@@ -135,5 +210,5 @@ export default function HSliderColorMobile(props) {
135
210
  boxShadow: 'none',
136
211
  pointerEvents: 'auto',
137
212
  }
138
- }, size: "small", value: props.saturationScore, step: 1, min: -100, max: 100, onChange: (_event, newValue) => props.onSaturationChange("saturationScore", newValue), onDoubleClick: () => props.onSaturationChange("saturationScore", 0) })] }) }));
213
+ }, size: "small", value: props.saturationScore, step: 1, min: -100, max: 100, onChange: (_event, newValue) => props.setSaturationScore("saturationScore", newValue), onDoubleClick: saturationInput.handleDoubleClick })] }) }));
139
214
  }
@@ -15,10 +15,10 @@ interface Props {
15
15
  contrastScore: number;
16
16
  clarityScore: number;
17
17
  sharpnessScore: number;
18
- onTempChange: (field: keyof AdjustmentState, value: number) => void;
19
- onTintChange: (field: keyof AdjustmentState, value: number) => void;
20
- onVibranceChange: (field: keyof AdjustmentState, value: number) => void;
21
- onSaturationChange: (field: keyof AdjustmentState, value: number) => void;
18
+ setTempScore: (field: keyof AdjustmentState, value: number) => void;
19
+ setTintScore: (field: keyof AdjustmentState, value: number) => void;
20
+ setVibranceScore: (field: keyof AdjustmentState, value: number) => void;
21
+ setSaturationScore: (field: keyof AdjustmentState, value: number) => void;
22
22
  onExposureChange: (field: keyof AdjustmentState, value: number) => void;
23
23
  onHighlightsChange: (field: keyof AdjustmentState, value: number) => void;
24
24
  onShadowsChange: (field: keyof AdjustmentState, value: number) => void;
@@ -4,5 +4,5 @@ import HSliderLightMobile from "./HSliderLightMobile";
4
4
  import HSliderDetailsMobile from "./HSliderDetailsMobile";
5
5
  import { Box } from "@mui/material";
6
6
  export default function HTabColorAdjustmentMobile(props) {
7
- return (_jsxs(Box, { ref: props.innerRef, children: [props.activeSubPanel === "light" && _jsx(HSliderLightMobile, { exposureScore: props.exposureScore, contrastScore: props.contrastScore, highlightsScore: props.highlightsScore, shadowScore: props.shadowScore, whiteScore: props.whiteScore, blackScore: props.blackScore, isBatchMode: props.isBatchMode, onExposureChange: props.onExposureChange, onContrastChange: props.onContrastChange, onHighlightsChange: props.onHighlightsChange, onShadowsChange: props.onShadowsChange, onWhitesChange: props.onWhitesChange, onBlacksChange: props.onBlacksChange, onDragStart: props.onDragStart, onDragEnd: props.onDragEnd }), props.activeSubPanel === "color" && _jsx(HSliderColorMobile, { tempScore: props.tempScore, tintScore: props.tintScore, vibranceScore: props.vibranceScore, saturationScore: props.saturationScore, isBatchMode: props.isBatchMode, onTempChange: props.onTempChange, onTintChange: props.onTintChange, onVibranceChange: props.onVibranceChange, onSaturationChange: props.onSaturationChange, onDragStart: props.onDragStart, onDragEnd: props.onDragEnd }), props.activeSubPanel === "details" && _jsx(HSliderDetailsMobile, { clarityScore: props.clarityScore, sharpnessScore: props.sharpnessScore, isBatchMode: props.isBatchMode, onClarityChange: props.onClarityChange, onSharpnessChange: props.onSharpnessChange, onDragStart: props.onDragStart, onDragEnd: props.onDragEnd })] }));
7
+ return (_jsxs(Box, { ref: props.innerRef, children: [props.activeSubPanel === "light" && _jsx(HSliderLightMobile, { exposureScore: props.exposureScore, contrastScore: props.contrastScore, highlightsScore: props.highlightsScore, shadowScore: props.shadowScore, whiteScore: props.whiteScore, blackScore: props.blackScore, isBatchMode: props.isBatchMode, onExposureChange: props.onExposureChange, onContrastChange: props.onContrastChange, onHighlightsChange: props.onHighlightsChange, onShadowsChange: props.onShadowsChange, onWhitesChange: props.onWhitesChange, onBlacksChange: props.onBlacksChange, onDragStart: props.onDragStart, onDragEnd: props.onDragEnd }), props.activeSubPanel === "color" && _jsx(HSliderColorMobile, { tempScore: props.tempScore, tintScore: props.tintScore, vibranceScore: props.vibranceScore, saturationScore: props.saturationScore, isBatchMode: props.isBatchMode, setTempScore: props.setTempScore, setTintScore: props.setTintScore, setVibranceScore: props.setVibranceScore, setSaturationScore: props.setSaturationScore, onDragStart: props.onDragStart, onDragEnd: props.onDragEnd }), props.activeSubPanel === "details" && _jsx(HSliderDetailsMobile, { clarityScore: props.clarityScore, sharpnessScore: props.sharpnessScore, isBatchMode: props.isBatchMode, onClarityChange: props.onClarityChange, onSharpnessChange: props.onSharpnessChange, onDragStart: props.onDragStart, onDragEnd: props.onDragEnd })] }));
8
8
  }
@@ -1 +1,2 @@
1
- export default function useSliderEvents(onDragStart: () => void, onDragEnd: () => void, isBatchMode: boolean): import("react").RefObject<HTMLSpanElement>;
1
+ import React from "react";
2
+ export default function useSliderEvents(onDragStart: () => void, onDragEnd: () => void, isBatchMode: boolean): React.RefObject<HTMLSpanElement>;
@@ -2,34 +2,31 @@ import { useEffect, useRef } from "react";
2
2
  export default function useSliderEvents(onDragStart, onDragEnd, isBatchMode) {
3
3
  const sliderRef = useRef(null);
4
4
  useEffect(() => {
5
- const sliderElement = sliderRef.current;
6
- if (!sliderElement)
5
+ const slider = sliderRef.current;
6
+ if (!slider)
7
7
  return;
8
+ // A single handler for starting the drag
8
9
  const handleStart = () => {
9
- // 1. When a drag STARTS on the slider...
10
10
  if (!isBatchMode) {
11
11
  onDragStart();
12
12
  }
13
- // 2. ...we add listeners to the whole DOCUMENT to catch the END of the drag.
14
- document.addEventListener("mouseup", handleEnd);
15
- document.addEventListener("touchend", handleEnd);
16
13
  };
14
+ // A single handler for ending the drag
17
15
  const handleEnd = () => {
18
- // 3. When the drag ends (anywhere on the page), we call onDragEnd...
19
16
  onDragEnd();
20
- // 4. ...and IMPORTANTLY, we clean up the document listeners.
21
- document.removeEventListener("mouseup", handleEnd);
22
- document.removeEventListener("touchend", handleEnd);
23
17
  };
24
- // Listen for the "start" events on the slider element itself
25
- sliderElement.addEventListener("mousedown", handleStart);
26
- sliderElement.addEventListener("touchstart", handleStart, { passive: true });
27
- // Cleanup function to remove all listeners when the component unmounts
18
+ // Listen for BOTH mouse and touch start events
19
+ slider.addEventListener('mousedown', handleStart);
20
+ slider.addEventListener('touchstart', handleStart, { passive: true });
21
+ // Listen for BOTH mouse and touch end events
22
+ slider.addEventListener('mouseup', handleEnd);
23
+ slider.addEventListener('touchend', handleEnd, { passive: true });
24
+ // Cleanup function to remove all listeners
28
25
  return () => {
29
- sliderElement.removeEventListener("mousedown", handleStart);
30
- sliderElement.removeEventListener("touchstart", handleStart);
31
- document.removeEventListener("mouseup", handleEnd);
32
- document.removeEventListener("touchend", handleEnd);
26
+ slider.removeEventListener('mousedown', handleStart);
27
+ slider.removeEventListener('touchstart', handleStart);
28
+ slider.removeEventListener('mouseup', handleEnd);
29
+ slider.removeEventListener('touchend', handleEnd);
33
30
  };
34
31
  }, [onDragStart, onDragEnd, isBatchMode]);
35
32
  return sliderRef;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yogiswara/honcho-editor-ui",
3
- "version": "2.10.14",
3
+ "version": "2.10.16",
4
4
  "description": "A complete UI component library for the Honcho photo editor.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -1,57 +0,0 @@
1
- import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
2
- import { Observable } from "rxjs/internal/Observable";
3
- export declare const api: any;
4
- export interface ResponseData<T> {
5
- code?: number;
6
- message?: string;
7
- data?: T;
8
- error_message?: string;
9
- }
10
- export declare class ResponseError extends Error {
11
- code: number;
12
- error_message: string;
13
- isEmptyData: boolean;
14
- constructor(code: number, error_message: string, originalError?: Error, isEmptyData?: boolean);
15
- }
16
- export declare class EmptyDataError extends Error {
17
- constructor();
18
- }
19
- export declare function handleResponse<T>(res: AxiosResponse<ResponseData<T>>): T;
20
- export declare function handleError(error: any): Observable<any>;
21
- export declare function isResponseError(error: any): Boolean;
22
- /**
23
- * @deprecated use axiosGetObservable, axiosPostObservable, axiosPutObservable, axiosDeleteObservable instead
24
- * @param promise
25
- */
26
- export declare function fromAxiosToObservable<T>(promise: Promise<AxiosResponse<ResponseData<T>>>): Observable<T>;
27
- export declare const apiV3: any;
28
- export declare class BaseServices {
29
- protected axios: AxiosInstance;
30
- protected constructor(axios: AxiosInstance);
31
- protected axiosGetObservable<T>(url: string, params?: AxiosRequestConfig<any> | undefined): Observable<T>;
32
- protected axiosPostObservable<T>(url: string, data: any, params?: AxiosRequestConfig<any> | undefined): Observable<T>;
33
- protected axiosPutObservable<T>(url: string, data: any, params?: AxiosRequestConfig<any> | undefined): Observable<T>;
34
- protected axiosDeleteObservable<T>(url: string, params?: AxiosRequestConfig<any> | undefined): Observable<T>;
35
- }
36
- export interface Result<T> {
37
- getStatus(): "loading" | "success" | "error" | "not-found" | "idle";
38
- getData(): T;
39
- getDataOrNull(): T | null | undefined;
40
- getError(): any;
41
- }
42
- export declare class ResultImpl<T> implements Result<T> {
43
- private readonly status;
44
- private readonly data;
45
- private readonly error;
46
- getStatus(): "loading" | "success" | "error" | "not-found" | "idle";
47
- getData(): T;
48
- getError(): any;
49
- getDataOrNull(): T | null | undefined;
50
- private constructor();
51
- static success<T>(data: T): Result<T>;
52
- static loading<T>(): Result<T>;
53
- static error<T>(err: any): Result<T>;
54
- static notFound<T>(): Result<T>;
55
- static idle<T>(): Result<T>;
56
- }
57
- export declare function fromPromise<T>(promise: Promise<T>): Observable<T>;
@@ -1,243 +0,0 @@
1
- import axios from "axios";
2
- import axiosRetry from 'axios-retry';
3
- import { Observable } from "rxjs/internal/Observable";
4
- import { catchError, from, map } from "rxjs";
5
- const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:8080";
6
- const apiConfig = (version) => {
7
- return axios.create({
8
- baseURL: `${BASE_URL}/${version}/`,
9
- timeout: 60000 * 2,
10
- });
11
- };
12
- export const api = axios.create({
13
- baseURL: `${BASE_URL}`,
14
- timeout: 60000 * 2,
15
- });
16
- axiosRetry(api, { retries: 3, retryDelay: axiosRetry.linearDelay() });
17
- export class ResponseError extends Error {
18
- constructor(code, error_message, originalError, isEmptyData = false) {
19
- super(`${code}: ${error_message}`);
20
- this.isEmptyData = false;
21
- this.code = code;
22
- this.error_message = error_message;
23
- this.isEmptyData = isEmptyData;
24
- if (originalError && originalError.stack) {
25
- this.stack += `\nCaused by: ${originalError.stack}`;
26
- }
27
- // we need to set prototype to make this object can check by
28
- // instanceof ResponseError
29
- Object.setPrototypeOf(this, ResponseError.prototype);
30
- }
31
- }
32
- export class EmptyDataError extends Error {
33
- constructor() {
34
- super("Data Empty, server not send any data in response");
35
- // we need to set prototype to make this object can check by
36
- // instanceof EmptyDataError
37
- Object.setPrototypeOf(this, EmptyDataError.prototype);
38
- }
39
- }
40
- // get data from response
41
- export function handleResponse(res) {
42
- if (!res.data.data) {
43
- throw new EmptyDataError();
44
- }
45
- return res.data.data;
46
- }
47
- function mapError(error) {
48
- if (error.isAxiosError) {
49
- if (error.response) {
50
- if (typeof error.response.data === "string") {
51
- return {
52
- code: error.response.status,
53
- message: `${error.response.status}: ${error.response.statusText}`,
54
- data: undefined,
55
- error_message: error.response.data,
56
- };
57
- }
58
- else {
59
- return error.response?.data;
60
- }
61
- }
62
- else if (error.request) {
63
- return {
64
- code: 400,
65
- message: "`${error.name}: failed connect to server check your connection`",
66
- data: undefined,
67
- error_message: "failed connect to server",
68
- };
69
- }
70
- else {
71
- return {
72
- code: 400,
73
- message: error.message,
74
- data: undefined,
75
- error_message: error.message,
76
- };
77
- }
78
- }
79
- else {
80
- return {
81
- code: 500,
82
- message: String(error),
83
- data: undefined,
84
- error_message: String(error),
85
- };
86
- }
87
- }
88
- // handle error from response convert it and throw it as ResponseError
89
- export function handleError(error) {
90
- if (error instanceof EmptyDataError) {
91
- // if data is empty just throw error
92
- throw new ResponseError(204, "Data Empty, server not send any data in response", error, true);
93
- }
94
- let response = mapError(error);
95
- throw new ResponseError(response.code || 500, response.error_message || "Unknown error", error);
96
- }
97
- export function isResponseError(error) {
98
- return !!((error.code) && (error.error_message));
99
- }
100
- /**
101
- * @deprecated use axiosGetObservable, axiosPostObservable, axiosPutObservable, axiosDeleteObservable instead
102
- * @param promise
103
- */
104
- export function fromAxiosToObservable(promise) {
105
- return from(promise).pipe(map(handleResponse), catchError(handleError));
106
- }
107
- export const apiV3 = apiConfig('v3');
108
- export class BaseServices {
109
- constructor(axios) {
110
- this.axios = axios;
111
- }
112
- axiosGetObservable(url, params) {
113
- return new Observable(subscriber => {
114
- const controller = new AbortController();
115
- const paramsData = { signal: controller.signal, ...params };
116
- this.axios.get(url, paramsData)
117
- .then(res => {
118
- console.debug({ res, url, params }, "success GET request");
119
- subscriber.next(res);
120
- subscriber.complete();
121
- })
122
- .catch((error) => {
123
- console.error({ error, url, params }, "Failed GET request");
124
- subscriber.error(error);
125
- });
126
- return () => {
127
- console.debug({ url, params, method: "GET" }, "Abort request");
128
- controller.abort();
129
- };
130
- }).pipe(map(handleResponse), catchError(handleError));
131
- }
132
- axiosPostObservable(url, data, params) {
133
- return new Observable(subscriber => {
134
- const controller = new AbortController();
135
- const paramsData = { signal: controller.signal, ...params };
136
- this.axios.post(url, data, paramsData)
137
- .then(res => {
138
- console.debug({ res, url, params }, "success POST request");
139
- subscriber.next(res);
140
- subscriber.complete();
141
- })
142
- .catch((error) => {
143
- console.error({ error, url, params }, "Failed POST request");
144
- subscriber.error(error);
145
- });
146
- return () => {
147
- console.debug({ url, params, method: "POST" }, "Abort request");
148
- controller.abort();
149
- };
150
- }).pipe(map(handleResponse), catchError(handleError));
151
- }
152
- axiosPutObservable(url, data, params) {
153
- return new Observable(subscriber => {
154
- const controller = new AbortController();
155
- const paramsData = { signal: controller.signal, ...params };
156
- this.axios.put(url, data, paramsData)
157
- .then(res => {
158
- console.debug({ res, url, params }, "success PUT request");
159
- subscriber.next(res);
160
- subscriber.complete();
161
- })
162
- .catch((error) => {
163
- console.error({ error, url, params }, "Failed PUT request");
164
- subscriber.error(error);
165
- });
166
- return () => {
167
- console.debug({ url, params, method: "PUT" }, "Abort request");
168
- controller.abort();
169
- };
170
- }).pipe(map(handleResponse), catchError(handleError));
171
- }
172
- axiosDeleteObservable(url, params) {
173
- return new Observable(subscriber => {
174
- const controller = new AbortController();
175
- const paramsData = { signal: controller.signal, ...params };
176
- this.axios.delete(url, paramsData)
177
- .then(res => {
178
- console.debug({ res, url, params }, "success DELETE request");
179
- subscriber.next(res);
180
- subscriber.complete();
181
- })
182
- .catch((error) => {
183
- console.error({ error, url, params }, "Failed DELETE request");
184
- subscriber.error(error);
185
- });
186
- return () => {
187
- console.debug({ url, params, method: "DELETE" }, "Abort request");
188
- controller.abort();
189
- };
190
- }).pipe(map(handleResponse), catchError(handleError));
191
- }
192
- }
193
- export class ResultImpl {
194
- getStatus() {
195
- return this.status;
196
- }
197
- getData() {
198
- if (this.data)
199
- return this.data;
200
- throw new Error("Data is not available");
201
- }
202
- getError() {
203
- if (this.error)
204
- return this.error;
205
- throw new Error("Error is not available");
206
- }
207
- getDataOrNull() {
208
- return this.data;
209
- }
210
- constructor(status, data, error) {
211
- this.status = "idle";
212
- this.status = status;
213
- this.data = data;
214
- this.error = error;
215
- }
216
- static success(data) {
217
- return new ResultImpl("success", data, null);
218
- }
219
- static loading() {
220
- return new ResultImpl("loading");
221
- }
222
- static error(err) {
223
- return new ResultImpl("error", null, err);
224
- }
225
- static notFound() {
226
- return new ResultImpl("not-found");
227
- }
228
- static idle() {
229
- return new ResultImpl("idle");
230
- }
231
- }
232
- export function fromPromise(promise) {
233
- return new Observable(subscriber => {
234
- promise.then(value => {
235
- console.debug({ value }, "Promise success");
236
- subscriber.next(value);
237
- subscriber.complete();
238
- }).catch(err => {
239
- console.error({ err }, "Promise error");
240
- subscriber.error(err);
241
- });
242
- });
243
- }