Compare commits
35 Commits
lavoce
...
a33c9b3b92
| Author | SHA1 | Date | |
|---|---|---|---|
| a33c9b3b92 | |||
| 58d1f5c7ab | |||
| c10a5bf62d | |||
| 6cc5042956 | |||
| 5079f8d316 | |||
| 7073390de7 | |||
| 4226a24e79 | |||
| 038009433f | |||
| 64ba51b17c | |||
| 47d0638a42 | |||
| d8c5f3ed44 | |||
| affd9146bb | |||
| 4022b3f8f4 | |||
| 446a4e2b95 | |||
| 83a475c708 | |||
| ab1c510a77 | |||
| 59859c6d18 | |||
| 2bd27937dc | |||
| 1058c660d6 | |||
| 35b2167791 | |||
| ec676983d0 | |||
| c07c5f8235 | |||
| b32ad97034 | |||
| 76244f6f6e | |||
| 0a128cbb3c | |||
| bd4ab26680 | |||
| 3e728a1ff5 | |||
| 9db143972e | |||
| 029ea269a7 | |||
| 4cdaa042da | |||
| 56af2a16c0 | |||
| deadf2ffb4 | |||
| 4da80c7089 | |||
| 56e3ce78a6 | |||
| 7c2a019dd2 |
@@ -4,7 +4,3 @@ VITE_MQTT_SERVER=ws://localhost:1884
|
|||||||
VITE_MQTT_USERNAME=
|
VITE_MQTT_USERNAME=
|
||||||
VITE_MQTT_PASSWORD=
|
VITE_MQTT_PASSWORD=
|
||||||
VITE_KEY_SESSION=PetekRombonganPetekMorekMorakMarek
|
VITE_KEY_SESSION=PetekRombonganPetekMorekMorakMarek
|
||||||
|
|
||||||
# VITE_WHATSAPP_URL=http://192.168.1.10:9531/qrview
|
|
||||||
VITE_WHATSAPP_URL=http://localhost:9531/qrview
|
|
||||||
# VITE_WHATSAPP_URL=https://117.102.231.130:9531/qrview
|
|
||||||
1
.gitignore
vendored
@@ -6,6 +6,7 @@ yarn-debug.log*
|
|||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
pnpm-debug.log*
|
pnpm-debug.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
|
*.config
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "antd-vite-react-call-of-duty",
|
"name": "antd-vite-react-sypiu",
|
||||||
"homepage": "/dashboard/home",
|
"homepage": "/dashboard/home",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host 0.0.0.0 --port 8592",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
|
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<system.webServer>
|
<system.webServer>
|
||||||
<rewrite>
|
<rewrite>
|
||||||
<rules>
|
<rules>
|
||||||
<rule name="reactViteSypiu">
|
<rule name="CallOfDuty">
|
||||||
<match url=".*" />
|
<match url=".*" />
|
||||||
<conditions logicalGrouping="MatchAll">
|
<conditions logicalGrouping="MatchAll">
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import IndexNotification from './pages/notification/IndexNotification';
|
|||||||
import IndexRole from './pages/role/IndexRole';
|
import IndexRole from './pages/role/IndexRole';
|
||||||
import IndexUser from './pages/user/IndexUser';
|
import IndexUser from './pages/user/IndexUser';
|
||||||
import IndexContact from './pages/contact/IndexContact';
|
import IndexContact from './pages/contact/IndexContact';
|
||||||
import IndexWhatsAppControl from './pages/whatsAppControl/IndexWhatsAppControl';
|
|
||||||
import DetailNotificationTab from './pages/notificationDetail/IndexNotificationDetail';
|
import DetailNotificationTab from './pages/notificationDetail/IndexNotificationDetail';
|
||||||
import IndexVerificationSparepart from './pages/verificationSparepart/IndexVerificationSparepart';
|
import IndexVerificationSparepart from './pages/verificationSparepart/IndexVerificationSparepart';
|
||||||
|
|
||||||
@@ -145,10 +144,6 @@ const App = () => {
|
|||||||
<Route index element={<IndexUser />} />
|
<Route index element={<IndexUser />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
<Route path="/whatsapp-control" element={<ProtectedRoute />}>
|
|
||||||
<Route index element={<IndexWhatsAppControl />} />
|
|
||||||
</Route>
|
|
||||||
|
|
||||||
<Route path="/contact" element={<ProtectedRoute />}>
|
<Route path="/contact" element={<ProtectedRoute />}>
|
||||||
<Route index element={<IndexContact />} />
|
<Route index element={<IndexContact />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|||||||
@@ -46,60 +46,10 @@ const getNotificationLogByNotificationId = async (notificationId) => {
|
|||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// update is_read status
|
|
||||||
const updateIsRead = async (notificationId) => {
|
|
||||||
const response = await SendRequest({
|
|
||||||
method: 'put',
|
|
||||||
prefix: `notification/${notificationId}`,
|
|
||||||
});
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Resend notification to specific user
|
|
||||||
const resendNotificationToUser = async (notificationId, userId) => {
|
|
||||||
const response = await SendRequest({
|
|
||||||
method: 'post',
|
|
||||||
prefix: `notification/${notificationId}/resend/${userId}`,
|
|
||||||
});
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Resend Chat by User
|
|
||||||
const resendChatByUser = async (notificationId, userPhone) => {
|
|
||||||
const response = await SendRequest({
|
|
||||||
method: 'post',
|
|
||||||
prefix: `notification-user/resend/${notificationId}/${userPhone}`,
|
|
||||||
});
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Resend Chat All User
|
|
||||||
const resendChatAllUser = async (notificationId) => {
|
|
||||||
const response = await SendRequest({
|
|
||||||
method: 'post',
|
|
||||||
prefix: `notification/resend/${notificationId}`,
|
|
||||||
});
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Searching
|
|
||||||
const searchData = async (queryParams) => {
|
|
||||||
const response = await SendRequest({
|
|
||||||
method: 'get',
|
|
||||||
prefix: `notification?criteria=${queryParams}`,
|
|
||||||
});
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getAllNotification,
|
getAllNotification,
|
||||||
getNotificationById,
|
getNotificationById,
|
||||||
getNotificationDetail,
|
getNotificationDetail,
|
||||||
createNotificationLog,
|
createNotificationLog,
|
||||||
getNotificationLogByNotificationId,
|
getNotificationLogByNotificationId
|
||||||
updateIsRead,
|
|
||||||
resendNotificationToUser,
|
|
||||||
resendChatByUser,
|
|
||||||
resendChatAllUser,
|
|
||||||
searchData,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
import { SendRequest } from '../components/Global/ApiRequest';
|
|
||||||
|
|
||||||
const resetWA = async () => {
|
|
||||||
const response = await SendRequest({
|
|
||||||
method: 'post',
|
|
||||||
prefix: `notifikasi-wa/restart-wa`,
|
|
||||||
});
|
|
||||||
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export { resetWA };
|
|
||||||
@@ -37,14 +37,17 @@
|
|||||||
<rect x="461.861" y="211.956" width="62.018" height="9.968" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="461.861" y="211.956" width="62.018" height="9.968" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px;" x="561" y="309.954" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Heater Temp SP</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px;" x="561" y="309.954" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Heater Temp SP</text>
|
||||||
<rect x="461.861" y="221.924" width="62.018" height="17.46" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="461.861" y="221.924" width="62.018" height="17.46" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
|
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="609.476" y="330.521" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">°F</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="609.476" y="330.521" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">°F</text>
|
||||||
<rect x="461.424" y="242.149" width="62.018" height="9.968" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="461.424" y="242.149" width="62.018" height="9.968" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px; stroke-width: 1;" x="567.471" y="352.188" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Heater Temp</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px; stroke-width: 1;" x="567.471" y="352.188" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Heater Temp</text>
|
||||||
<rect x="461.424" y="252.117" width="62.018" height="17.46" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="461.424" y="252.117" width="62.018" height="17.46" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
|
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="608.947" y="373.755" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">°F</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="608.947" y="373.755" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">°F</text>
|
||||||
<rect x="535.456" y="242.272" width="62.018" height="9.968" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="535.456" y="242.272" width="62.018" height="9.968" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px; stroke-width: 1;" x="659" y="352.363" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Heater Temp</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px; stroke-width: 1;" x="659" y="352.363" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Heater Temp</text>
|
||||||
<rect x="535.456" y="252.24" width="62.018" height="17.46" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="535.456" y="252.24" width="62.018" height="17.46" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
|
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="698.476" y="373.93" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">°C</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="698.476" y="373.93" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">°C</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1; font-weight: bold;" x="748" y="347.676" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">HEATER</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1; font-weight: bold;" x="748" y="347.676" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">HEATER</text>
|
||||||
<path style="fill: none; stroke: rgb(0, 0, 0); stroke-width: 1.525; transform-origin: 678.512px 258.693px;" d="M 678.467 229.321 L 678.558 288.066" transform="matrix(0, 1.184039, -0.844567, 0, -0.000022, -0.000005)"/>
|
<path style="fill: none; stroke: rgb(0, 0, 0); stroke-width: 1.525; transform-origin: 678.512px 258.693px;" d="M 678.467 229.321 L 678.558 288.066" transform="matrix(0, 1.184039, -0.844567, 0, -0.000022, -0.000005)"/>
|
||||||
@@ -107,10 +110,12 @@
|
|||||||
<rect x="427.269" y="377.282" width="62.018" height="9.968" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="427.269" y="377.282" width="62.018" height="9.968" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px; stroke-width: 1;" x="532.167" y="545.681" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Dew Temp</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px; stroke-width: 1;" x="532.167" y="545.681" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Dew Temp</text>
|
||||||
<rect x="427.269" y="387.25" width="62.018" height="17.46" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="427.269" y="387.25" width="62.018" height="17.46" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
|
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="567.643" y="567.248" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">°C</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="567.643" y="567.248" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">°C</text>
|
||||||
<rect x="427.27" y="412.201" width="62.018" height="9.968" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="427.27" y="412.201" width="62.018" height="9.968" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px; stroke-width: 1;" x="532.168" y="595.681" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Dew Temp</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px; stroke-width: 1;" x="532.168" y="595.681" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Dew Temp</text>
|
||||||
<rect x="427.27" y="422.169" width="62.018" height="17.46" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="427.27" y="422.169" width="62.018" height="17.46" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
|
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="567.644" y="617.248" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">°F</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="567.644" y="617.248" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">°F</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px; stroke-width: 1; text-anchor: middle; font-weight: bolder;" x="602.463" y="573.003" transform="matrix(0.826913, 0, 0, 0.698383, 24.207672, -7.192523)">AIR<tspan x="602.4630126953125" dy="1em"></tspan>OUTLET</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 9px; stroke-width: 1; text-anchor: middle; font-weight: bolder;" x="602.463" y="573.003" transform="matrix(0.826913, 0, 0, 0.698383, 24.207672, -7.192523)">AIR<tspan x="602.4630126953125" dy="1em"></tspan>OUTLET</text>
|
||||||
<g transform="matrix(-0.387768, 0, 0, -0.200385, 743.634644, -199.991287)" style="transform-origin: 72.2405px 412.5px;">
|
<g transform="matrix(-0.387768, 0, 0, -0.200385, 743.634644, -199.991287)" style="transform-origin: 72.2405px 412.5px;">
|
||||||
@@ -174,36 +179,43 @@
|
|||||||
<rect x="43.443" y="280.75" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="43.443" y="280.75" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="53.987" y="423.091" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">RUN HOUR</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="53.987" y="423.091" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">RUN HOUR</text>
|
||||||
<rect x="126.135" y="280.75" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.135" y="280.75" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
|
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225" y="424.066" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225" y="424.066" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
||||||
<rect x="43.443" y="308.191" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="43.443" y="308.191" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; stroke-width: 1; font-weight: bold;" x="53.987" y="461.382" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">PURGE HOUR</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; stroke-width: 1; font-weight: bold;" x="53.987" y="461.382" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">PURGE HOUR</text>
|
||||||
<rect x="126.135" y="308.191" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.135" y="308.191" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
|
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225" y="463.357" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225" y="463.357" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
||||||
<rect x="43.443" y="333.129" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="43.443" y="333.129" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 12px; font-weight: 700; white-space: pre;" x="53.987" y="498.091" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">HEATER HOUR</text>
|
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 12px; font-weight: 700; white-space: pre;" x="53.987" y="498.091" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">HEATER HOUR</text>
|
||||||
<rect x="126.135" y="333.129" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.135" y="333.129" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
|
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225" y="499.066" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225" y="499.066" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
||||||
<rect x="43.65" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(248, 213, 14);"/>
|
<rect x="43.65" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(248, 213, 14);"/>
|
||||||
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; font-weight: 700; white-space: pre; stroke-width: 1;" x="54.237" y="536.777" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Alarm Info</text>
|
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; font-weight: 700; white-space: pre; stroke-width: 1;" x="54.237" y="536.777" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Alarm Info</text>
|
||||||
<rect x="126.341" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.341" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="159.3" y="537.792" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4501">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="159.3" y="537.792" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225.25" y="537.752" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225.25" y="537.752" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
||||||
<rect x="43.443" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="43.443" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="56.987" y="250.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">RT or LT Dry</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="56.987" y="250.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">RT or LT Dry</text>
|
||||||
<rect x="126.135" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.135" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="180.05" y="251.6" transform="matrix(0.826913, 0, 0, 0.698383, -3.902357, 3.138935)" id="c_4022">#######</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="180.05" y="251.6" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">LT Dry</text>
|
||||||
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="177" y="251.56" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">RT Dry</text>
|
||||||
<rect x="43.443" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="43.443" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; stroke-width: 1; font-weight: bold;" x="53.987" y="288.876" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Opmode</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; stroke-width: 1; font-weight: bold;" x="53.987" y="288.876" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Opmode</text>
|
||||||
<rect x="126.135" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.135" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, -0.902357, 3.138935)" id="c_4015">#####</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">HTD</text>
|
||||||
<rect x="43.443" y="214.051" width="165.383" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="43.443" y="214.051" width="165.383" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; font-weight: 700; white-space: pre; stroke-width: 1;" x="53.987" y="322.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Step</text>
|
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; font-weight: 700; white-space: pre; stroke-width: 1;" x="53.987" y="322.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Step</text>
|
||||||
|
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="233" y="323.56" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">s</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="233" y="323.56" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">s</text>
|
||||||
<rect x="43.443" y="241.422" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="43.443" y="241.422" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; font-weight: 700; white-space: pre; stroke-width: 1;" x="54.237" y="364.271" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Cycle Timer</text>
|
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; font-weight: 700; white-space: pre; stroke-width: 1;" x="54.237" y="364.271" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Cycle Timer</text>
|
||||||
<rect x="126.341" y="241.068" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.341" y="241.068" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
|
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225.25" y="365.246" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">s</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225.25" y="365.246" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">s</text>
|
||||||
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; font-weight: 700; white-space: pre; stroke-width: 1;" x="141.894" y="324.069" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Time</text>
|
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; font-weight: 700; white-space: pre; stroke-width: 1;" x="141.894" y="324.069" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Time</text>
|
||||||
|
|
||||||
<rect x="870.356" y="142.816" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="870.356" y="142.816" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="1060.06" y="224.103" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Dryer Status</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="1060.06" y="224.103" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Dryer Status</text>
|
||||||
<rect x="870.356" y="170.304" width="82.691" height="42.35" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="870.356" y="170.304" width="82.691" height="42.35" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
@@ -217,10 +229,17 @@
|
|||||||
<rect x="870.356" y="344.9" width="82.691" height="42.35" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="870.356" y="344.9" width="82.691" height="42.35" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.702" cy="366.997" rx="20.673" ry="17.46"/>
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.702" cy="366.997" rx="20.673" ry="17.46"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="380.451" y="296.591" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="380.451" y="296.591" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
||||||
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.483" rx="13.582" ry="12.517"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="379.214" y="423.395" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="379.214" y="423.395" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
||||||
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.418" cy="321.016" rx="13.582" ry="12.517"/>
|
||||||
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.623" cy="320.662" rx="13.582" ry="12.517" id="c_4021"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="897.237" y="299.014" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="897.237" y="299.014" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
||||||
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="761.772" cy="233.876" rx="13.582" ry="12.517"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="896" y="425.818" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="896" y="425.818" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
||||||
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.96" cy="322.354" rx="13.582" ry="12.517"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 35px; stroke-width: 1; font-weight: bold;" x="348.875" y="78.242" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">AIR DRYER UNIT A (01-CL-10532-A)</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 35px; stroke-width: 1; font-weight: bold;" x="348.875" y="78.242" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">AIR DRYER UNIT A (01-CL-10532-A)</text>
|
||||||
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, 1.386371, 4.000207)">HTLS</text>
|
||||||
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, -1.613663, 3.937793)">BLWR</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.447" y="617.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4005">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.447" y="617.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4005">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.446" y="567.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4004">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.446" y="567.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4004">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="653.279" y="373.97" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4001">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="653.279" y="373.97" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4001">####.##</text>
|
||||||
@@ -232,16 +251,11 @@
|
|||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="177.05" y="323.6" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4008">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="177.05" y="323.6" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4008">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="168.775" y="365.807" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4007">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="168.775" y="365.807" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4007">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="92.151" y="325.554" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4006">##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="92.151" y="325.554" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_4006">##</text>
|
||||||
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.483" rx="13.582" ry="12.517" id="c_4018"/>
|
||||||
<ellipse style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(255, 172, 63);" cx="640.283" cy="271.689" rx="9.717" ry="7.689" id="c_4019"/>
|
<ellipse style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(255, 172, 63);" cx="640.283" cy="271.689" rx="9.717" ry="7.689" id="c_4019"/>
|
||||||
<ellipse style="fill: rgb(63, 255, 69); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.254" cy="192.696" rx="20.673" ry="17.46" id="c_4016"/>
|
<ellipse style="fill: rgb(63, 255, 69); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.254" cy="192.696" rx="20.673" ry="17.46" id="c_4016"/>
|
||||||
<ellipse style="fill: rgb(255, 159, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="279.12" rx="20.673" ry="17.46" id="c_4017"/>
|
<ellipse style="fill: rgb(255, 159, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="279.12" rx="20.673" ry="17.46" id="c_4017"/>
|
||||||
<ellipse style="fill: rgb(255, 63, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="366.862" rx="20.673" ry="17.46" id="c_4020"/>
|
<ellipse style="fill: rgb(255, 63, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="366.862" rx="20.673" ry="17.46" id="c_4020"/>
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.483" rx="13.582" ry="12.517" id="c_4018"/>
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.685" cy="322.259" rx="13.582" ry="12.517" id="c_4018"/>
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.96" cy="322.354" rx="13.582" ry="12.517" id="c_4018"/>
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.031" cy="234.094" rx="13.582" ry="12.517" id="c_4021"/>
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.418" cy="321.016" rx="13.582" ry="12.517" id="c_4021"/>
|
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="763.772" cy="237.876" rx="13.582" ry="12.517" id="c_4021"/>
|
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.483" rx="13.582" ry="12.517" id=""/>
|
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.418" cy="320.687" rx="13.582" ry="12.517" id="-2"/>
|
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="763.418" cy="322.259" rx="13.582" ry="12.517" id="c_-2"/>
|
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="763.418" cy="237.483" rx="13.582" ry="12.517" id="c_-3"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
@@ -186,16 +186,17 @@
|
|||||||
<rect x="43.65" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(248, 213, 14);"/>
|
<rect x="43.65" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(248, 213, 14);"/>
|
||||||
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; font-weight: 700; white-space: pre; stroke-width: 1;" x="54.237" y="536.777" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Alarm Info</text>
|
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; font-weight: 700; white-space: pre; stroke-width: 1;" x="54.237" y="536.777" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Alarm Info</text>
|
||||||
<rect x="126.341" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.341" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="159.3" y="537.792" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5501">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="159.3" y="537.792" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225.25" y="537.752" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225.25" y="537.752" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
||||||
<rect x="43.443" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="43.443" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="56.987" y="250.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">RT or LT Dry</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="56.987" y="250.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">RT or LT Dry</text>
|
||||||
<rect x="126.135" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.135" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="180.05" y="251.6" transform="matrix(0.826913, 0, 0, 0.698383, -3.902357, 3.138935)" id="c_5022">#######</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="180.05" y="251.6" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">LT Dry</text>
|
||||||
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="177" y="251.56" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">RT Dry</text>
|
||||||
<rect x="43.443" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="43.443" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; stroke-width: 1; font-weight: bold;" x="53.987" y="288.876" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Opmode</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; stroke-width: 1; font-weight: bold;" x="53.987" y="288.876" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Opmode</text>
|
||||||
<rect x="126.135" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.135" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, 0.097643, 3.138935)" id="c_5015">#####</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">HTD</text>
|
||||||
<rect x="43.443" y="214.051" width="165.383" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="43.443" y="214.051" width="165.383" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; font-weight: 700; white-space: pre; stroke-width: 1;" x="53.987" y="322.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Step</text>
|
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; font-weight: 700; white-space: pre; stroke-width: 1;" x="53.987" y="322.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Step</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="233" y="323.56" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">s</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="233" y="323.56" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">s</text>
|
||||||
@@ -217,10 +218,16 @@
|
|||||||
<rect x="870.356" y="344.9" width="82.691" height="42.35" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="870.356" y="344.9" width="82.691" height="42.35" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.702" cy="366.997" rx="20.673" ry="17.46"/>
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.702" cy="366.997" rx="20.673" ry="17.46"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="380.451" y="296.591" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="380.451" y="296.591" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
||||||
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.483" rx="13.582" ry="12.517"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="379.214" y="423.395" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="379.214" y="423.395" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
||||||
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.418" cy="321.016" rx="13.582" ry="12.517"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="897.237" y="299.014" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="897.237" y="299.014" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
||||||
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="761.772" cy="233.876" rx="13.582" ry="12.517"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="896" y="425.818" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="896" y="425.818" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
||||||
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.96" cy="322.354" rx="13.582" ry="12.517"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 35px; stroke-width: 1; font-weight: bold;" x="348.875" y="78.242" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">AIR DRYER UNIT B (01-CL-10535-B)</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 35px; stroke-width: 1; font-weight: bold;" x="348.875" y="78.242" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">AIR DRYER UNIT B (01-CL-10535-B)</text>
|
||||||
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, 1.386371, 4.000207)">HTLS</text>
|
||||||
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, -1.613663, 3.937793)">BLWR</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.447" y="617.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5005">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.447" y="617.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5005">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.446" y="567.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5004">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.446" y="567.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5004">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="653.279" y="373.97" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5001">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="653.279" y="373.97" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5001">####.##</text>
|
||||||
@@ -232,16 +239,12 @@
|
|||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="177.05" y="323.6" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5008">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="177.05" y="323.6" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5008">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="168.775" y="365.807" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5007">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="168.775" y="365.807" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5007">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="92.151" y="325.554" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5006">##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="92.151" y="325.554" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_5006">##</text>
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.517" rx="13.582" ry="12.517" id=""/>
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.483" rx="13.582" ry="12.517" id="c_5018"/>
|
||||||
<ellipse style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(255, 172, 63);" cx="640.283" cy="271.689" rx="9.717" ry="7.689" id="c_5019"/>
|
<ellipse style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(255, 172, 63);" cx="640.283" cy="271.689" rx="9.717" ry="7.689" id="c_5019"/>
|
||||||
<ellipse style="fill: rgb(63, 255, 69); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.254" cy="192.696" rx="20.673" ry="17.46" id="c_5016"/>
|
<ellipse style="fill: rgb(63, 255, 69); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.254" cy="192.696" rx="20.673" ry="17.46" id="c_5016"/>
|
||||||
<ellipse style="fill: rgb(255, 159, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="279.12" rx="20.673" ry="17.46" id="c_5017"/>
|
<ellipse style="fill: rgb(255, 159, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="279.12" rx="20.673" ry="17.46" id="c_5017"/>
|
||||||
<ellipse style="fill: rgb(255, 63, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="366.862" rx="20.673" ry="17.46" id="c_5020"/>
|
<ellipse style="fill: rgb(255, 63, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="366.862" rx="20.673" ry="17.46" id="c_5020"/>
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.483" rx="13.582" ry="12.517" id="c_5018"/>
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.623" cy="320.662" rx="13.582" ry="12.517" id="c_5021"/>
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.96" cy="322.354" rx="13.582" ry="12.517" id="c_5018"/>
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.685" cy="322.259" rx="13.582" ry="12.517" id="c_5018"/>
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.418" cy="321.016" rx="13.582" ry="12.517" id="c_5021"/>
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.031" cy="234.094" rx="13.582" ry="12.517" id="c_5021"/>
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="761.772" cy="233.876" rx="13.582" ry="12.517" id="c_5021"/>
|
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.418" cy="320.662" rx="13.582" ry="12.517" id=""/>
|
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="763.418" cy="322.125" rx="13.582" ry="12.517" id="c_-2"/>
|
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="761.418" cy="234.26" rx="13.582" ry="12.517" id="c_-3"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
@@ -186,16 +186,17 @@
|
|||||||
<rect x="43.65" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(248, 213, 14);"/>
|
<rect x="43.65" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(248, 213, 14);"/>
|
||||||
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; font-weight: 700; white-space: pre; stroke-width: 1;" x="54.237" y="536.777" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Alarm Info</text>
|
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; font-weight: 700; white-space: pre; stroke-width: 1;" x="54.237" y="536.777" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Alarm Info</text>
|
||||||
<rect x="126.341" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.341" y="360.147" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="159.3" y="537.792" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6501">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="159.3" y="537.792" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225.25" y="537.752" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="225.25" y="537.752" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">H</text>
|
||||||
<rect x="43.443" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="43.443" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="56.987" y="250.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">RT or LT Dry</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="56.987" y="250.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">RT or LT Dry</text>
|
||||||
<rect x="126.135" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.135" y="160.275" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="180.05" y="251.6" transform="matrix(0.826913, 0, 0, 0.698383, -3.902357, 3.138935)" id="c_6022">#######</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="180.05" y="251.6" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">LT Dry</text>
|
||||||
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="177" y="251.56" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">RT Dry</text>
|
||||||
<rect x="43.443" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
<rect x="43.443" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); fill: rgb(120, 231, 228); stroke-width: 0.763;"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; stroke-width: 1; font-weight: bold;" x="53.987" y="288.876" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Opmode</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; stroke-width: 1; font-weight: bold;" x="53.987" y="288.876" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Opmode</text>
|
||||||
<rect x="126.135" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="126.135" y="187.715" width="82.691" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, -1.902357, 3.138935)" id="c_6015">#####</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">HTD</text>
|
||||||
<rect x="43.443" y="214.051" width="165.383" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="43.443" y="214.051" width="165.383" height="27.103" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; font-weight: 700; white-space: pre; stroke-width: 1;" x="53.987" y="322.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Step</text>
|
<text style="fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 13px; font-weight: 700; white-space: pre; stroke-width: 1;" x="53.987" y="322.585" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">Step</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="233" y="323.56" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">s</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="233" y="323.56" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">s</text>
|
||||||
@@ -217,10 +218,17 @@
|
|||||||
<rect x="870.356" y="344.9" width="82.691" height="42.35" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
<rect x="870.356" y="344.9" width="82.691" height="42.35" style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(244, 248, 248);"/>
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.702" cy="366.997" rx="20.673" ry="17.46"/>
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.702" cy="366.997" rx="20.673" ry="17.46"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="380.451" y="296.591" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="380.451" y="296.591" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
||||||
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.483" rx="13.582" ry="12.517"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="379.214" y="423.395" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="379.214" y="423.395" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
||||||
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.418" cy="321.016" rx="13.582" ry="12.517"/>
|
||||||
|
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="897.237" y="299.014" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="897.237" y="299.014" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">REGEN</text>
|
||||||
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="761.772" cy="233.876" rx="13.582" ry="12.517"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="896" y="425.818" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 14px; stroke-width: 1; font-weight: bold;" x="896" y="425.818" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">DRYING</text>
|
||||||
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.96" cy="322.354" rx="13.582" ry="12.517"/>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 35px; stroke-width: 1; font-weight: bold;" x="348.875" y="78.242" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">AIR DRYER UNIT C (01-CL-10539-C)</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Bahnschrift; font-size: 35px; stroke-width: 1; font-weight: bold;" x="348.875" y="78.242" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)">AIR DRYER UNIT C (01-CL-10539-C)</text>
|
||||||
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, 1.386371, 4.000207)">HTLS</text>
|
||||||
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="183.349" y="288.807" transform="matrix(0.826913, 0, 0, 0.698383, -1.613663, 3.937793)">BLWR</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.447" y="617.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6005">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.447" y="617.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6005">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.446" y="567.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6004">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="522.446" y="567.288" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6004">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="653.279" y="373.97" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6001">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 12px; stroke-width: 1;" x="653.279" y="373.97" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6001">####.##</text>
|
||||||
@@ -232,16 +240,12 @@
|
|||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="177.05" y="323.6" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6008">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="177.05" y="323.6" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6008">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="168.775" y="365.807" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6007">####.##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="168.775" y="365.807" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6007">####.##</text>
|
||||||
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="92.151" y="325.554" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6006">##</text>
|
<text style="white-space: pre; fill: rgb(51, 51, 51); font-family: Arial, sans-serif; font-size: 15px; stroke-width: 1;" x="92.151" y="325.554" transform="matrix(0.826913, 0, 0, 0.698383, 2.097643, 3.138935)" id="c_6006">##</text>
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.517" rx="13.582" ry="12.517" id=""/>
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.483" rx="13.582" ry="12.517" id="c_6018"/>
|
||||||
<ellipse style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(255, 172, 63);" cx="640.283" cy="271.689" rx="9.717" ry="7.689" id="c_6019"/>
|
<ellipse style="stroke: rgb(0, 0, 0); stroke-width: 0.763; fill: rgb(255, 172, 63);" cx="640.283" cy="271.689" rx="9.717" ry="7.689" id="c_6019"/>
|
||||||
<ellipse style="fill: rgb(63, 255, 69); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.254" cy="192.696" rx="20.673" ry="17.46" id="c_6016"/>
|
<ellipse style="fill: rgb(63, 255, 69); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.254" cy="192.696" rx="20.673" ry="17.46" id="c_6016"/>
|
||||||
<ellipse style="fill: rgb(255, 159, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="279.12" rx="20.673" ry="17.46" id="c_6017"/>
|
<ellipse style="fill: rgb(255, 159, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="279.12" rx="20.673" ry="17.46" id="c_6017"/>
|
||||||
<ellipse style="fill: rgb(255, 63, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="366.862" rx="20.673" ry="17.46" id="c_6020"/>
|
<ellipse style="fill: rgb(255, 63, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="911.352" cy="366.862" rx="20.673" ry="17.46" id="c_6020"/>
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="336.418" cy="237.483" rx="13.582" ry="12.517" id="c_6018"/>
|
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.685" cy="322.259" rx="13.582" ry="12.517" id="c_6018"/>
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.96" cy="322.354" rx="13.582" ry="12.517" id="c_6018"/>
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.623" cy="320.662" rx="13.582" ry="12.517" id="c_6021"/>
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.418" cy="321.016" rx="13.582" ry="12.517" id="c_6021"/>
|
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="762.031" cy="234.094" rx="13.582" ry="12.517" id="c_6021"/>
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="761.418" cy="237.483" rx="13.582" ry="12.517" id="c_6021"/>
|
|
||||||
<ellipse style="fill: rgb(255, 204, 63); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="763.418" cy="322.692" rx="13.582" ry="12.517" id="c_-2"/>
|
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="335.418" cy="321.095" rx="13.582" ry="12.517" id=""/>
|
|
||||||
<ellipse style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); stroke-width: 0.763;" cx="761.418" cy="237.483" rx="13.582" ry="12.517" id="c_-3"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 177 KiB |
@@ -30,18 +30,18 @@ instance.interceptors.response.use(
|
|||||||
originalRequest._retry = true;
|
originalRequest._retry = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// console.log('🔄 Refresh token dipanggil...');
|
console.log('🔄 Refresh token dipanggil...');
|
||||||
const refreshRes = await refreshApi.post('/auth/refresh-token');
|
const refreshRes = await refreshApi.post('/auth/refresh-token');
|
||||||
|
|
||||||
const newAccessToken = refreshRes.data.data.accessToken;
|
const newAccessToken = refreshRes.data.data.accessToken;
|
||||||
localStorage.setItem('token', newAccessToken);
|
localStorage.setItem('token', newAccessToken);
|
||||||
// console.log('✅ Token refreshed successfully');
|
console.log('✅ Token refreshed successfully');
|
||||||
|
|
||||||
// update token di header
|
// update token di header
|
||||||
instance.defaults.headers.common['Authorization'] = `Bearer ${newAccessToken}`;
|
instance.defaults.headers.common['Authorization'] = `Bearer ${newAccessToken}`;
|
||||||
originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`;
|
originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`;
|
||||||
|
|
||||||
// console.log('🔁 Retrying original request...');
|
console.log('🔁 Retrying original request...');
|
||||||
return instance(originalRequest);
|
return instance(originalRequest);
|
||||||
} catch (refreshError) {
|
} catch (refreshError) {
|
||||||
console.error(
|
console.error(
|
||||||
@@ -85,20 +85,20 @@ async function ApiRequest({ method = 'GET', params = {}, prefix = '/', token = t
|
|||||||
if (token && rawToken) {
|
if (token && rawToken) {
|
||||||
const cleanToken = rawToken.replace(/"/g, '');
|
const cleanToken = rawToken.replace(/"/g, '');
|
||||||
request.headers['Authorization'] = `Bearer ${cleanToken}`;
|
request.headers['Authorization'] = `Bearer ${cleanToken}`;
|
||||||
// console.log('🔐 Sending request with token:', cleanToken.substring(0, 20) + '...');
|
console.log('🔐 Sending request with token:', cleanToken.substring(0, 20) + '...');
|
||||||
} else {
|
} else {
|
||||||
console.warn('⚠️ No token found in localStorage');
|
console.warn('⚠️ No token found in localStorage');
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('📤 API Request:', { method, url: prefix, hasToken: !!rawToken });
|
console.log('📤 API Request:', { method, url: prefix, hasToken: !!rawToken });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await instance(request);
|
const response = await instance(request);
|
||||||
// console.log('✅ API Response:', {
|
console.log('✅ API Response:', {
|
||||||
// url: prefix,
|
url: prefix,
|
||||||
// status: response.status,
|
status: response.status,
|
||||||
// statusCode: response.data?.statusCode,
|
statusCode: response.data?.statusCode,
|
||||||
// });
|
});
|
||||||
return { ...response, error: false };
|
return { ...response, error: false };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const status = error?.response?.status || 500;
|
const status = error?.response?.status || 500;
|
||||||
@@ -143,10 +143,17 @@ async function cekError(status, message = '') {
|
|||||||
const SendRequest = async (queryParams) => {
|
const SendRequest = async (queryParams) => {
|
||||||
try {
|
try {
|
||||||
const response = await ApiRequest(queryParams);
|
const response = await ApiRequest(queryParams);
|
||||||
|
console.log('📦 SendRequest response:', {
|
||||||
|
hasError: response.error,
|
||||||
|
status: response.status,
|
||||||
|
statusCode: response.data?.statusCode,
|
||||||
|
data: response.data,
|
||||||
|
});
|
||||||
|
|
||||||
// If ApiRequest returned error flag, return error structure
|
// If ApiRequest returned error flag, return error structure
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
const errorMsg = response.data?.message || response.statusText || 'Request failed';
|
const errorMsg = response.data?.message || response.statusText || 'Request failed';
|
||||||
|
console.error('❌ SendRequest error response:', errorMsg);
|
||||||
|
|
||||||
// Return consistent error structure instead of empty array
|
// Return consistent error structure instead of empty array
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -2,17 +2,7 @@
|
|||||||
import mqtt from 'mqtt';
|
import mqtt from 'mqtt';
|
||||||
|
|
||||||
const mqttUrl = `${import.meta.env.VITE_MQTT_SERVER ?? 'ws://localhost:1884'}`;
|
const mqttUrl = `${import.meta.env.VITE_MQTT_SERVER ?? 'ws://localhost:1884'}`;
|
||||||
const topics = [
|
const topics = ['cod/air_dryer/air_dryer1'];
|
||||||
'PIU_COD/AIR_DRYER/OVERVIEW',
|
|
||||||
'PIU_COD/AIR_DRYER/AIR_DRYER_A',
|
|
||||||
'PIU_COD/AIR_DRYER/AIR_DRYER_B',
|
|
||||||
'PIU_COD/AIR_DRYER/AIR_DRYER_C',
|
|
||||||
'PIU_COD/COMPRESSOR/OVERVIEW',
|
|
||||||
'PIU_COD/COMPRESSOR/COMPRESSOR_A',
|
|
||||||
'PIU_COD/COMPRESSOR/COMPRESSOR_B',
|
|
||||||
'PIU_COD/COMPRESSOR/COMPRESSOR_C',
|
|
||||||
'PIU_COD/ERROR_CODE/SIM',
|
|
||||||
];
|
|
||||||
const options = {
|
const options = {
|
||||||
keepalive: 30,
|
keepalive: 30,
|
||||||
clientId: 'react_mqtt_' + Math.random().toString(16).substr(2, 8),
|
clientId: 'react_mqtt_' + Math.random().toString(16).substr(2, 8),
|
||||||
@@ -74,97 +64,29 @@ const listenMessage = (callback) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const colorIds = ['c_1023', 'c_2023', 'c_2023'];
|
|
||||||
const StatusColor = (el, num) => {
|
|
||||||
switch (num) {
|
|
||||||
case 1:
|
|
||||||
el.style.fill = 'orange';
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
el.style.fill = 'rgb(7,250,14)';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
el.style.fill = 'rgb(216,216,216)';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const dryerIds = ['c_4018', 'c_4021', 'c_5018', 'c_5021', 'c_6018', 'c_6021'];
|
|
||||||
const handleBoolean = (svg, el, value) => {
|
|
||||||
if (!dryerIds.includes(el.id)) {
|
|
||||||
el.style.display = value ? '' : 'none';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const i = dryerIds.indexOf(el.id);
|
|
||||||
const id1 = dryerIds[i - (i % 2)];
|
|
||||||
const id2 = dryerIds[i - (i % 2) + 1];
|
|
||||||
|
|
||||||
const el1 = svg.getElementById(id1);
|
|
||||||
const el2 = svg.getElementById(id2);
|
|
||||||
|
|
||||||
if (!el1 || !el2) return;
|
|
||||||
|
|
||||||
el1.style.fill = value ? 'rgb(216,216,216)' : 'yellow';
|
|
||||||
el2.style.fill = value ? 'yellow' : 'rgb(216,216,216)';
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNumber = (el, value) => {
|
|
||||||
const num = Number(value);
|
|
||||||
|
|
||||||
if (colorIds.includes(el.id)) {
|
|
||||||
StatusColor(el, num);
|
|
||||||
} else {
|
|
||||||
el.textContent = num.toFixed(2);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOther = (el, value) => {
|
|
||||||
el.textContent = value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setValSvg = (listenTopic, svg) => {
|
const setValSvg = (listenTopic, svg) => {
|
||||||
client.on('message', (topic, message) => {
|
client.on('message', (topic, message) => {
|
||||||
|
// console.log(topic ,' = ', listenTopic);
|
||||||
if (topic === listenTopic) {
|
if (topic === listenTopic) {
|
||||||
const objChanel = JSON.parse(message);
|
const objChanel = JSON.parse(message);
|
||||||
|
|
||||||
Object.entries(objChanel).forEach(([key, value]) => {
|
Object.entries(objChanel).forEach(([key, value]) => {
|
||||||
|
// console.log(key, value);
|
||||||
const el = svg.getElementById(key);
|
const el = svg.getElementById(key);
|
||||||
|
if (el) {
|
||||||
if (!el) return;
|
if (value === true) {
|
||||||
// else if (el.id === 'c_2014' || el.id === 'c_2024') {
|
el.style.display = ''; // sembunyikan
|
||||||
// el.setAttribute('text-anchor', 'middle');
|
} else if (value === false) {
|
||||||
// el.setAttribute('x', '10%');
|
el.style.display = 'none';
|
||||||
// }
|
|
||||||
if (typeof value === 'boolean') {
|
|
||||||
handleBoolean(svg, el, value);
|
|
||||||
} else if (!isNaN(value)) {
|
} else if (!isNaN(value)) {
|
||||||
handleNumber(el, value);
|
el.textContent = Number(value ?? 0.0).toFixed(2);
|
||||||
} else {
|
} else {
|
||||||
handleOther(el, value);
|
el.textContent = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const target = svg.querySelector('text[x="225.25"][y="537.752"]');
|
|
||||||
if (target) target.remove();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// === NOTIFICATION LISTENER ===
|
export { publishMessage, listenMessage, setValSvg };
|
||||||
const notifListeners = [];
|
|
||||||
|
|
||||||
const onNotifUpdate = (callback) => {
|
|
||||||
notifListeners.push(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
client.on('message', (topic, message) => {
|
|
||||||
if (topic === import.meta.env.VITE_MQTT_TOPIC_COD) {
|
|
||||||
try {
|
|
||||||
const payload = JSON.parse(message.toString());
|
|
||||||
notifListeners.forEach((cb) => cb(payload));
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Invalid notif payload', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export { publishMessage, listenMessage, setValSvg, onNotifUpdate };
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
DatabaseOutlined,
|
DatabaseOutlined,
|
||||||
SettingOutlined,
|
SettingOutlined,
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
GlobalOutlined,
|
|
||||||
AntDesignOutlined,
|
AntDesignOutlined,
|
||||||
ShoppingCartOutlined,
|
ShoppingCartOutlined,
|
||||||
ShoppingOutlined,
|
ShoppingOutlined,
|
||||||
@@ -37,14 +36,6 @@ import {
|
|||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
const host = window.location.hostname;
|
|
||||||
|
|
||||||
const isLocal =
|
|
||||||
host === '127.0.0.1' ||
|
|
||||||
host === 'localhost' ||
|
|
||||||
host.startsWith('192.168.') ||
|
|
||||||
host.startsWith('10.') ||
|
|
||||||
host.startsWith('172.');
|
|
||||||
|
|
||||||
const allItems = [
|
const allItems = [
|
||||||
{
|
{
|
||||||
@@ -234,19 +225,6 @@ const allItems = [
|
|||||||
</Link>
|
</Link>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
...(isLocal
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
key: 'whatsapp-control',
|
|
||||||
icon: <GlobalOutlined style={{ fontSize: '19px' }} />,
|
|
||||||
label: (
|
|
||||||
<Link to="/whatsapp-control" className="fontMenus">
|
|
||||||
WhatsApp Control
|
|
||||||
</Link>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
// {
|
// {
|
||||||
// key: 'jadwal-shift',
|
// key: 'jadwal-shift',
|
||||||
// icon: <CalendarOutlined style={{ fontSize: '19px' }} />,
|
// icon: <CalendarOutlined style={{ fontSize: '19px' }} />,
|
||||||
@@ -272,7 +250,6 @@ const LayoutMenu = () => {
|
|||||||
if (pathname === '/dashboard/home') return 'home';
|
if (pathname === '/dashboard/home') return 'home';
|
||||||
if (pathname === '/user') return 'user';
|
if (pathname === '/user') return 'user';
|
||||||
if (pathname === '/role') return 'role';
|
if (pathname === '/role') return 'role';
|
||||||
if (pathname === '/whatsapp-control') return 'whatsapp-control';
|
|
||||||
if (pathname === '/notification') return 'notification';
|
if (pathname === '/notification') return 'notification';
|
||||||
if (pathname === '/jadwal-shift') return 'jadwal-shift';
|
if (pathname === '/jadwal-shift') return 'jadwal-shift';
|
||||||
if (pathname === '/contact') return 'contact';
|
if (pathname === '/contact') return 'contact';
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export default function RedirectWa() {
|
|||||||
|
|
||||||
console.log('tes', response);
|
console.log('tes', response);
|
||||||
|
|
||||||
const tokenResult = JSON.stringify(response.data?.data?.accessToken);
|
const tokenResult = JSON.stringify(response.data?.accessToken);
|
||||||
|
|
||||||
sessionStorage.setItem('token_redirect', tokenResult);
|
sessionStorage.setItem('token_redirect', tokenResult);
|
||||||
response.data.auth = true;
|
response.data.auth = true;
|
||||||
|
|||||||
@@ -267,6 +267,9 @@ const ListContact = memo(function ListContact(props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backend doesn't support is_active filter or order parameter
|
||||||
|
// Contact hanya supports: criteria, name, code, limit, page
|
||||||
|
|
||||||
const queryParams = new URLSearchParams();
|
const queryParams = new URLSearchParams();
|
||||||
Object.entries(searchParams).forEach(([key, value]) => {
|
Object.entries(searchParams).forEach(([key, value]) => {
|
||||||
if (value !== '' && value !== null && value !== undefined) {
|
if (value !== '' && value !== null && value !== undefined) {
|
||||||
@@ -306,10 +309,11 @@ const ListContact = memo(function ListContact(props) {
|
|||||||
// Listen for saved contact data
|
// Listen for saved contact data
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.lastSavedContact) {
|
if (props.lastSavedContact) {
|
||||||
fetchContacts();
|
fetchContacts(); // Refetch all contacts when data is saved
|
||||||
}
|
}
|
||||||
}, [props.lastSavedContact]);
|
}, [props.lastSavedContact]);
|
||||||
|
|
||||||
|
// Get contacts (already filtered by backend)
|
||||||
const getFilteredContacts = () => {
|
const getFilteredContacts = () => {
|
||||||
return filteredContacts;
|
return filteredContacts;
|
||||||
};
|
};
|
||||||
@@ -322,7 +326,7 @@ const ListContact = memo(function ListContact(props) {
|
|||||||
const showAddModal = () => {
|
const showAddModal = () => {
|
||||||
props.setSelectedData(null);
|
props.setSelectedData(null);
|
||||||
props.setActionMode('add');
|
props.setActionMode('add');
|
||||||
|
// Pass the current active tab to determine contact type
|
||||||
props.setContactType?.(activeTab);
|
props.setContactType?.(activeTab);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import filePathSvg from '../../assets/svg/air_dryer_A_rev.svg';
|
|||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
// const filePathSvg = '/src/assets/svg/air_dryer_A_rev.svg';
|
// const filePathSvg = '/src/assets/svg/air_dryer_A_rev.svg';
|
||||||
const topicMqtt = 'PIU_COD/AIR_DRYER/AIR_DRYER_A';
|
const topicMqtt = 'PIU_GGCP/Devices/PB';
|
||||||
|
|
||||||
const SvgAirDryerA = () => {
|
const SvgAirDryerA = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import filePathSvg from '../../assets/svg/air_dryer_B_rev.svg';
|
|||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
// const filePathSvg = '/src/assets/svg/air_dryer_B_rev.svg';
|
// const filePathSvg = '/src/assets/svg/air_dryer_B_rev.svg';
|
||||||
const topicMqtt = 'PIU_COD/AIR_DRYER/AIR_DRYER_B';
|
const topicMqtt = 'PIU_GGCP/Devices/PB';
|
||||||
|
|
||||||
const SvgAirDryerB = () => {
|
const SvgAirDryerB = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import filePathSvg from '../../assets/svg/air_dryer_C_rev.svg';
|
|||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
// const filePathSvg = '/src/assets/svg/air_dryer_C_rev.svg';
|
// const filePathSvg = '/src/assets/svg/air_dryer_C_rev.svg';
|
||||||
const topicMqtt = 'PIU_COD/AIR_DRYER/AIR_DRYER_C';
|
const topicMqtt = 'PIU_GGCP/Devices/PB';
|
||||||
|
|
||||||
const SvgAirDryerC = () => {
|
const SvgAirDryerC = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import filePathSvg from '../../assets/svg/compressorA_rev.svg';
|
|||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
// const filePathSvg = '/src/assets/svg/test-new.svg';
|
// const filePathSvg = '/src/assets/svg/test-new.svg';
|
||||||
const topicMqtt = 'PIU_COD/COMPRESSOR/COMPRESSOR_A';
|
const topicMqtt = 'PIU_GGCP/Devices/PB';
|
||||||
|
|
||||||
const SvgCompressorA = () => {
|
const SvgCompressorA = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import SvgViewer from './SvgViewer';
|
|||||||
import filePathSvg from '../../assets/svg/compressorB_rev.svg';
|
import filePathSvg from '../../assets/svg/compressorB_rev.svg';
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
const topicMqtt = 'PIU_COD/COMPRESSOR/COMPRESSOR_B';
|
const topicMqtt = 'cod/air_dryer/air_dryer1';
|
||||||
|
|
||||||
const SvgCompressorB = () => {
|
const SvgCompressorB = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import filePathSvg from '../../assets/svg/compressorC_rev.svg';
|
|||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
// const filePathSvg = '/src/assets/svg/test-new.svg';
|
// const filePathSvg = '/src/assets/svg/test-new.svg';
|
||||||
const topicMqtt = 'PIU_COD/COMPRESSOR/COMPRESSOR_C';
|
const topicMqtt = 'PIU_GGCP/Devices/PB';
|
||||||
|
|
||||||
const SvgCompressorC = () => {
|
const SvgCompressorC = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import filePathSvg from '../../assets/svg/overview-airdryer.svg';
|
|||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
// const filePathSvg = '/src/assets/svg/test-new.svg';
|
// const filePathSvg = '/src/assets/svg/test-new.svg';
|
||||||
const topicMqtt = 'PIU_COD/AIR_DRYER/OVERVIEW';
|
const topicMqtt = 'PIU_GGCP/Devices/PB';
|
||||||
|
|
||||||
const SvgOverviewAirDryer = () => {
|
const SvgOverviewAirDryer = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import filePathSvg from '../../assets/svg/overview-compressor.svg';
|
|||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
// const filePathSvg = '/src/assets/svg/test-new.svg';
|
// const filePathSvg = '/src/assets/svg/test-new.svg';
|
||||||
const topicMqtt = 'PIU_COD/COMPRESSOR/OVERVIEW';
|
const topicMqtt = 'PIU_GGCP/Devices/PB';
|
||||||
|
|
||||||
const SvgOverviewCompressor = () => {
|
const SvgOverviewCompressor = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -13,18 +13,13 @@ import {
|
|||||||
Space,
|
Space,
|
||||||
ConfigProvider,
|
ConfigProvider,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import { EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
import {
|
||||||
|
EditOutlined,
|
||||||
|
DeleteOutlined
|
||||||
|
} from '@ant-design/icons';
|
||||||
import { NotifAlert, NotifOk, NotifConfirmDialog } from '../../../components/Global/ToastNotif';
|
import { NotifAlert, NotifOk, NotifConfirmDialog } from '../../../components/Global/ToastNotif';
|
||||||
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
|
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
|
||||||
import {
|
import { getBrandById, createBrand, createErrorCode, getErrorCodesByBrandId, updateErrorCode, deleteErrorCode, deleteBrand } from '../../../api/master-brand';
|
||||||
getBrandById,
|
|
||||||
createBrand,
|
|
||||||
createErrorCode,
|
|
||||||
getErrorCodesByBrandId,
|
|
||||||
updateErrorCode,
|
|
||||||
deleteErrorCode,
|
|
||||||
deleteBrand,
|
|
||||||
} from '../../../api/master-brand';
|
|
||||||
import BrandForm from './component/BrandForm';
|
import BrandForm from './component/BrandForm';
|
||||||
import ErrorCodeForm from './component/ErrorCodeForm';
|
import ErrorCodeForm from './component/ErrorCodeForm';
|
||||||
import SolutionForm from './component/SolutionForm';
|
import SolutionForm from './component/SolutionForm';
|
||||||
@@ -47,9 +42,7 @@ const AddBrandDevice = () => {
|
|||||||
const [selectedSparepartIds, setSelectedSparepartIds] = useState([]);
|
const [selectedSparepartIds, setSelectedSparepartIds] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const tab = searchParams.get('tab');
|
const tab = searchParams.get('tab');
|
||||||
const [currentStep, setCurrentStep] = useState(
|
const [currentStep, setCurrentStep] = useState(tab === 'error-codes' ? 1 : (location.state?.phase || 0));
|
||||||
tab === 'error-codes' ? 1 : location.state?.phase || 0
|
|
||||||
);
|
|
||||||
const [editingErrorCodeKey, setEditingErrorCodeKey] = useState(null);
|
const [editingErrorCodeKey, setEditingErrorCodeKey] = useState(null);
|
||||||
const [isErrorCodeFormReadOnly, setIsErrorCodeFormReadOnly] = useState(false);
|
const [isErrorCodeFormReadOnly, setIsErrorCodeFormReadOnly] = useState(false);
|
||||||
const [searchText, setSearchText] = useState('');
|
const [searchText, setSearchText] = useState('');
|
||||||
@@ -75,7 +68,7 @@ const AddBrandDevice = () => {
|
|||||||
const values = solutionForm.getFieldsValue(true);
|
const values = solutionForm.getFieldsValue(true);
|
||||||
const solutions = [];
|
const solutions = [];
|
||||||
|
|
||||||
solutionFields.forEach((fieldKey) => {
|
solutionFields.forEach(fieldKey => {
|
||||||
let solution = null;
|
let solution = null;
|
||||||
|
|
||||||
if (values.solution_items && values.solution_items[fieldKey]) {
|
if (values.solution_items && values.solution_items[fieldKey]) {
|
||||||
@@ -92,16 +85,9 @@ const AddBrandDevice = () => {
|
|||||||
if (solutionType === 'text') {
|
if (solutionType === 'text') {
|
||||||
isValid = solution.text && solution.text.trim() !== '';
|
isValid = solution.text && solution.text.trim() !== '';
|
||||||
} else if (solutionType === 'file') {
|
} else if (solutionType === 'file') {
|
||||||
const hasPathSolution =
|
const hasPathSolution = solution.path_solution && solution.path_solution.trim() !== '';
|
||||||
solution.path_solution && solution.path_solution.trim() !== '';
|
const hasFileUpload = (solution.fileUpload && typeof solution.fileUpload === 'object' && Object.keys(solution.fileUpload).length > 0);
|
||||||
const hasFileUpload =
|
const hasFile = (solution.file && typeof solution.file === 'object' && Object.keys(solution.file).length > 0);
|
||||||
solution.fileUpload &&
|
|
||||||
typeof solution.fileUpload === 'object' &&
|
|
||||||
Object.keys(solution.fileUpload).length > 0;
|
|
||||||
const hasFile =
|
|
||||||
solution.file &&
|
|
||||||
typeof solution.file === 'object' &&
|
|
||||||
Object.keys(solution.file).length > 0;
|
|
||||||
isValid = hasPathSolution || hasFileUpload || hasFile;
|
isValid = hasPathSolution || hasFileUpload || hasFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,9 +118,9 @@ const AddBrandDevice = () => {
|
|||||||
text: '',
|
text: '',
|
||||||
status: true,
|
status: true,
|
||||||
file: null,
|
file: null,
|
||||||
fileUpload: null,
|
fileUpload: null
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
@@ -142,6 +128,7 @@ const AddBrandDevice = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const setSolutionsForExistingRecord = (solutions, targetForm) => {
|
const setSolutionsForExistingRecord = (solutions, targetForm) => {
|
||||||
|
|
||||||
if (!targetForm || !solutions || solutions.length === 0) {
|
if (!targetForm || !solutions || solutions.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -166,14 +153,11 @@ const AddBrandDevice = () => {
|
|||||||
fileObject = {
|
fileObject = {
|
||||||
uploadPath: solution.path_solution || solution.path_document,
|
uploadPath: solution.path_solution || solution.path_document,
|
||||||
path_solution: solution.path_solution || solution.path_document,
|
path_solution: solution.path_solution || solution.path_document,
|
||||||
name:
|
name: solution.file_upload_name || (solution.path_solution || solution.path_document).split('/').pop() || 'File',
|
||||||
solution.file_upload_name ||
|
|
||||||
(solution.path_solution || solution.path_document).split('/').pop() ||
|
|
||||||
'File',
|
|
||||||
type_solution: solution.type_solution,
|
type_solution: solution.type_solution,
|
||||||
isExisting: true,
|
isExisting: true,
|
||||||
size: 0,
|
size: 0,
|
||||||
url: solution.path_solution || solution.path_document,
|
url: solution.path_solution || solution.path_document
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +170,7 @@ const AddBrandDevice = () => {
|
|||||||
file: fileObject,
|
file: fileObject,
|
||||||
fileUpload: fileObject,
|
fileUpload: fileObject,
|
||||||
path_solution: solution.path_solution || solution.path_document || null,
|
path_solution: solution.path_solution || solution.path_document || null,
|
||||||
fileName: solution.file_upload_name || null,
|
fileName: solution.file_upload_name || null
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -196,35 +180,28 @@ const AddBrandDevice = () => {
|
|||||||
|
|
||||||
setSolutionStatuses(newSolutionStatuses);
|
setSolutionStatuses(newSolutionStatuses);
|
||||||
|
|
||||||
|
|
||||||
targetForm.resetFields();
|
targetForm.resetFields();
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
targetForm.setFieldsValue({
|
targetForm.setFieldsValue({
|
||||||
solution_items: solutionItems,
|
solution_items: solutionItems
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Object.keys(solutionItems).forEach((key) => {
|
Object.keys(solutionItems).forEach(key => {
|
||||||
const solution = solutionItems[key];
|
const solution = solutionItems[key];
|
||||||
targetForm.setFieldValue(['solution_items', key, 'name'], solution.name);
|
targetForm.setFieldValue(['solution_items', key, 'name'], solution.name);
|
||||||
targetForm.setFieldValue(['solution_items', key, 'type'], solution.type);
|
targetForm.setFieldValue(['solution_items', key, 'type'], solution.type);
|
||||||
targetForm.setFieldValue(['solution_items', key, 'text'], solution.text);
|
targetForm.setFieldValue(['solution_items', key, 'text'], solution.text);
|
||||||
targetForm.setFieldValue(['solution_items', key, 'file'], solution.file);
|
targetForm.setFieldValue(['solution_items', key, 'file'], solution.file);
|
||||||
targetForm.setFieldValue(
|
targetForm.setFieldValue(['solution_items', key, 'fileUpload'], solution.fileUpload);
|
||||||
['solution_items', key, 'fileUpload'],
|
|
||||||
solution.fileUpload
|
|
||||||
);
|
|
||||||
targetForm.setFieldValue(['solution_items', key, 'status'], solution.status);
|
targetForm.setFieldValue(['solution_items', key, 'status'], solution.status);
|
||||||
targetForm.setFieldValue(
|
targetForm.setFieldValue(['solution_items', key, 'path_solution'], solution.path_solution);
|
||||||
['solution_items', key, 'path_solution'],
|
targetForm.setFieldValue(['solution_items', key, 'fileName'], solution.fileName);
|
||||||
solution.path_solution
|
|
||||||
);
|
|
||||||
targetForm.setFieldValue(
|
|
||||||
['solution_items', key, 'fileName'],
|
|
||||||
solution.fileName
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const finalValues = targetForm.getFieldsValue();
|
const finalValues = targetForm.getFieldsValue();
|
||||||
}, 100);
|
}, 100);
|
||||||
}, 100);
|
}, 100);
|
||||||
@@ -232,14 +209,14 @@ const AddBrandDevice = () => {
|
|||||||
|
|
||||||
const handleAddSolutionField = () => {
|
const handleAddSolutionField = () => {
|
||||||
const newKey = Math.max(...solutionFields, 0) + 1;
|
const newKey = Math.max(...solutionFields, 0) + 1;
|
||||||
setSolutionFields((prev) => [...prev, newKey]);
|
setSolutionFields(prev => [...prev, newKey]);
|
||||||
setSolutionTypes((prev) => ({ ...prev, [newKey]: 'text' }));
|
setSolutionTypes(prev => ({ ...prev, [newKey]: 'text' }));
|
||||||
setSolutionStatuses((prev) => ({ ...prev, [newKey]: true }));
|
setSolutionStatuses(prev => ({ ...prev, [newKey]: true }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveSolutionField = (fieldKey) => {
|
const handleRemoveSolutionField = (fieldKey) => {
|
||||||
if (solutionFields.length > 1) {
|
if (solutionFields.length > 1) {
|
||||||
setSolutionFields((prev) => prev.filter((key) => key !== fieldKey));
|
setSolutionFields(prev => prev.filter(key => key !== fieldKey));
|
||||||
const newTypes = { ...solutionTypes };
|
const newTypes = { ...solutionTypes };
|
||||||
const newStatuses = { ...solutionStatuses };
|
const newStatuses = { ...solutionStatuses };
|
||||||
delete newTypes[fieldKey];
|
delete newTypes[fieldKey];
|
||||||
@@ -256,7 +233,7 @@ const AddBrandDevice = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSolutionTypeChange = (fieldKey, type) => {
|
const handleSolutionTypeChange = (fieldKey, type) => {
|
||||||
setSolutionTypes((prev) => ({ ...prev, [fieldKey]: type }));
|
setSolutionTypes(prev => ({ ...prev, [fieldKey]: type }));
|
||||||
|
|
||||||
if (type === 'file') {
|
if (type === 'file') {
|
||||||
solutionForm.setFieldValue(['solution_items', fieldKey, 'text'], '');
|
solutionForm.setFieldValue(['solution_items', fieldKey, 'text'], '');
|
||||||
@@ -269,7 +246,7 @@ const AddBrandDevice = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSolutionStatusChange = (fieldKey, status) => {
|
const handleSolutionStatusChange = (fieldKey, status) => {
|
||||||
setSolutionStatuses((prev) => ({ ...prev, [fieldKey]: status }));
|
setSolutionStatuses(prev => ({ ...prev, [fieldKey]: status }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNextStep = async () => {
|
const handleNextStep = async () => {
|
||||||
@@ -282,7 +259,7 @@ const AddBrandDevice = () => {
|
|||||||
brand_type: brandValues.brand_type || '',
|
brand_type: brandValues.brand_type || '',
|
||||||
brand_manufacture: brandValues.brand_manufacture || '',
|
brand_manufacture: brandValues.brand_manufacture || '',
|
||||||
brand_model: brandValues.brand_model || '',
|
brand_model: brandValues.brand_model || '',
|
||||||
is_active: brandValues.is_active !== undefined ? brandValues.is_active : true,
|
is_active: brandValues.is_active !== undefined ? brandValues.is_active : true
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await createBrand(brandApiData);
|
const response = await createBrand(brandApiData);
|
||||||
@@ -291,7 +268,7 @@ const AddBrandDevice = () => {
|
|||||||
const newBrandInfo = {
|
const newBrandInfo = {
|
||||||
...brandValues,
|
...brandValues,
|
||||||
brand_id: response.data.brand_id,
|
brand_id: response.data.brand_id,
|
||||||
brand_code: response.data.brand_code,
|
brand_code: response.data.brand_code
|
||||||
};
|
};
|
||||||
setBrandInfo(newBrandInfo);
|
setBrandInfo(newBrandInfo);
|
||||||
setTemporaryBrandId(response.data.brand_id);
|
setTemporaryBrandId(response.data.brand_id);
|
||||||
@@ -330,7 +307,8 @@ const AddBrandDevice = () => {
|
|||||||
if (isTemporaryBrand && temporaryBrandId) {
|
if (isTemporaryBrand && temporaryBrandId) {
|
||||||
try {
|
try {
|
||||||
await deleteBrand(temporaryBrandId);
|
await deleteBrand(temporaryBrandId);
|
||||||
} catch (error) {}
|
} catch (error) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
navigate('/master/brand-device');
|
navigate('/master/brand-device');
|
||||||
};
|
};
|
||||||
@@ -382,6 +360,8 @@ const AddBrandDevice = () => {
|
|||||||
setTrigerFilter((prev) => !prev);
|
setTrigerFilter((prev) => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const resetErrorCodeForm = () => {
|
const resetErrorCodeForm = () => {
|
||||||
errorCodeForm.resetFields();
|
errorCodeForm.resetFields();
|
||||||
errorCodeForm.setFieldsValue({
|
errorCodeForm.setFieldsValue({
|
||||||
@@ -411,16 +391,16 @@ const AddBrandDevice = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (!solutionData || solutionData.length === 0) {
|
if (!solutionData || solutionData.length === 0) {
|
||||||
// NotifAlert({
|
NotifAlert({
|
||||||
// icon: 'warning',
|
icon: 'warning',
|
||||||
// title: 'Perhatian',
|
title: 'Perhatian',
|
||||||
// message: 'Setiap error code harus memiliki minimal 1 solution!',
|
message: 'Setiap error code harus memiliki minimal 1 solution!',
|
||||||
// });
|
});
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
const formattedSolutions = solutionData.map((solution) => {
|
const formattedSolutions = solutionData.map(solution => {
|
||||||
const solutionType = solution.type || 'text';
|
const solutionType = solution.type || 'text';
|
||||||
|
|
||||||
let typeSolution = solutionType === 'text' ? 'text' : 'image';
|
let typeSolution = solutionType === 'text' ? 'text' : 'image';
|
||||||
@@ -442,11 +422,7 @@ const AddBrandDevice = () => {
|
|||||||
} else {
|
} else {
|
||||||
formattedSolution.text_solution = '';
|
formattedSolution.text_solution = '';
|
||||||
|
|
||||||
formattedSolution.path_solution =
|
formattedSolution.path_solution = solution.path_solution || solution.file?.uploadPath || solution.fileUpload?.uploadPath || '';
|
||||||
solution.path_solution ||
|
|
||||||
solution.file?.uploadPath ||
|
|
||||||
solution.fileUpload?.uploadPath ||
|
|
||||||
'';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formattedSolution.brand_code_solution_id) {
|
if (formattedSolution.brand_code_solution_id) {
|
||||||
@@ -464,7 +440,7 @@ const AddBrandDevice = () => {
|
|||||||
path_icon: errorCodeIcon?.uploadPath || '',
|
path_icon: errorCodeIcon?.uploadPath || '',
|
||||||
is_active: errorCodeValues.status === undefined ? true : errorCodeValues.status,
|
is_active: errorCodeValues.status === undefined ? true : errorCodeValues.status,
|
||||||
solution: formattedSolutions,
|
solution: formattedSolutions,
|
||||||
spareparts: selectedSparepartIds || [],
|
spareparts: selectedSparepartIds || []
|
||||||
};
|
};
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
@@ -480,13 +456,11 @@ const AddBrandDevice = () => {
|
|||||||
NotifOk({
|
NotifOk({
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
title: 'Berhasil',
|
title: 'Berhasil',
|
||||||
message: editingErrorCodeKey
|
message: editingErrorCodeKey ? 'Error code berhasil diupdate!' : 'Error code berhasil ditambahkan!',
|
||||||
? 'Error code berhasil diupdate!'
|
|
||||||
: 'Error code berhasil ditambahkan!',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
resetErrorCodeForm();
|
resetErrorCodeForm();
|
||||||
setTrigerFilter((prev) => !prev);
|
setTrigerFilter(prev => !prev);
|
||||||
} else {
|
} else {
|
||||||
NotifAlert({
|
NotifAlert({
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
@@ -505,10 +479,12 @@ const AddBrandDevice = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleErrorCodeIconRemove = () => {
|
const handleErrorCodeIconRemove = () => {
|
||||||
setErrorCodeIcon(null);
|
setErrorCodeIcon(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleFinish = async () => {
|
const handleFinish = async () => {
|
||||||
setConfirmLoading(true);
|
setConfirmLoading(true);
|
||||||
try {
|
try {
|
||||||
@@ -530,10 +506,10 @@ const AddBrandDevice = () => {
|
|||||||
const response = await getErrorCodesByBrandId(brandInfo.brand_id, queryParams);
|
const response = await getErrorCodesByBrandId(brandInfo.brand_id, queryParams);
|
||||||
|
|
||||||
if (response && response.statusCode === 200 && response.data) {
|
if (response && response.statusCode === 200 && response.data) {
|
||||||
const freshErrorCodes = response.data.map((ec) => ({
|
const freshErrorCodes = response.data.map(ec => ({
|
||||||
...ec,
|
...ec,
|
||||||
tempId: `existing_${ec.error_code_id}`,
|
tempId: `existing_${ec.error_code_id}`,
|
||||||
status: 'existing',
|
status: 'existing'
|
||||||
}));
|
}));
|
||||||
setApiErrorCodes(freshErrorCodes);
|
setApiErrorCodes(freshErrorCodes);
|
||||||
|
|
||||||
@@ -541,8 +517,7 @@ const AddBrandDevice = () => {
|
|||||||
NotifAlert({
|
NotifAlert({
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
title: 'Perhatian',
|
title: 'Perhatian',
|
||||||
message:
|
message: 'Harap tambahkan minimal 1 error code sebelum menyelesaikan.',
|
||||||
'Harap tambahkan minimal 1 error code sebelum menyelesaikan.',
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -551,8 +526,7 @@ const AddBrandDevice = () => {
|
|||||||
NotifAlert({
|
NotifAlert({
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
title: 'Perhatian',
|
title: 'Perhatian',
|
||||||
message:
|
message: 'Harap tambahkan minimal 1 error code sebelum menyelesaikan.',
|
||||||
'Harap tambahkan minimal 1 error code sebelum menyelesaikan.',
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -617,7 +591,11 @@ const AddBrandDevice = () => {
|
|||||||
<Spin size="large" />
|
<Spin size="large" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<BrandForm form={brandForm} isEdit={false} brandInfo={brandInfo} />
|
<BrandForm
|
||||||
|
form={brandForm}
|
||||||
|
isEdit={false}
|
||||||
|
brandInfo={brandInfo}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -657,39 +635,31 @@ const AddBrandDevice = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col xs={24} md={16} lg={16}>
|
<Col xs={24} md={16} lg={16}>
|
||||||
<div
|
<div style={{
|
||||||
style={{
|
paddingLeft: '12px'
|
||||||
paddingLeft: '12px',
|
}}>
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Card
|
<Card
|
||||||
title={
|
title={
|
||||||
<div
|
<div style={{
|
||||||
style={{
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
width: '100%',
|
width: '100%'
|
||||||
}}
|
}}>
|
||||||
>
|
<span style={{
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: '#262626',
|
color: '#262626',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: '8px',
|
gap: '8px'
|
||||||
}}
|
}}>
|
||||||
>
|
<span style={{
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
width: '4px',
|
width: '4px',
|
||||||
height: '20px',
|
height: '20px',
|
||||||
backgroundColor: '#23A55A',
|
backgroundColor: '#23A55A',
|
||||||
borderRadius: '2px',
|
borderRadius: '2px'
|
||||||
}}
|
}}></span>
|
||||||
></span>
|
|
||||||
Error Code Form
|
Error Code Form
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<Button
|
||||||
@@ -705,51 +675,43 @@ const AddBrandDevice = () => {
|
|||||||
padding: '0 24px',
|
padding: '0 24px',
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
boxShadow: '0 2px 4px rgba(35, 165, 90, 0.2)',
|
boxShadow: '0 2px 4px rgba(35, 165, 90, 0.2)',
|
||||||
transition: 'all 0.3s ease',
|
transition: 'all 0.3s ease'
|
||||||
}}
|
}}
|
||||||
onMouseEnter={(e) => {
|
onMouseEnter={(e) => {
|
||||||
e.target.style.boxShadow =
|
e.target.style.boxShadow = '0 4px 8px rgba(35, 165, 90, 0.3)';
|
||||||
'0 4px 8px rgba(35, 165, 90, 0.3)';
|
|
||||||
}}
|
}}
|
||||||
onMouseLeave={(e) => {
|
onMouseLeave={(e) => {
|
||||||
e.target.style.boxShadow =
|
e.target.style.boxShadow = '0 2px 4px rgba(35, 165, 90, 0.2)';
|
||||||
'0 2px 4px rgba(35, 165, 90, 0.2)';
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{editingErrorCodeKey
|
{editingErrorCodeKey ? 'Update Error Code' : 'Save Error Code'}
|
||||||
? 'Update Error Code'
|
|
||||||
: 'Save Error Code'}
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
boxShadow: '0 2px 8px rgba(0,0,0,0.06)',
|
boxShadow: '0 2px 8px rgba(0,0,0,0.06)',
|
||||||
borderRadius: '12px',
|
borderRadius: '12px'
|
||||||
}}
|
}}
|
||||||
styles={{
|
styles={{
|
||||||
body: { padding: '16px 24px 12px 24px' },
|
body: { padding: '16px 24px 12px 24px' },
|
||||||
header: {
|
header: {
|
||||||
padding: '16px 24px',
|
padding: '16px 24px',
|
||||||
borderBottom: '1px solid #f0f0f0',
|
borderBottom: '1px solid #f0f0f0',
|
||||||
backgroundColor: '#fafafa',
|
backgroundColor: '#fafafa'
|
||||||
},
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
||||||
style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}
|
<div style={{
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
padding: '16px',
|
padding: '16px',
|
||||||
border: '1px solid #f0f0f0',
|
border: '1px solid #f0f0f0',
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
backgroundColor: '#ffffff',
|
backgroundColor: '#ffffff',
|
||||||
marginBottom: '0',
|
marginBottom: '0',
|
||||||
transition: 'all 0.3s ease',
|
transition: 'all 0.3s ease',
|
||||||
boxShadow: '0 1px 3px rgba(0,0,0,0.04)',
|
boxShadow: '0 1px 3px rgba(0,0,0,0.04)'
|
||||||
}}
|
}}>
|
||||||
>
|
|
||||||
<ErrorCodeForm
|
<ErrorCodeForm
|
||||||
errorCodeForm={errorCodeForm}
|
errorCodeForm={errorCodeForm}
|
||||||
isErrorCodeFormReadOnly={isErrorCodeFormReadOnly}
|
isErrorCodeFormReadOnly={isErrorCodeFormReadOnly}
|
||||||
@@ -762,42 +724,29 @@ const AddBrandDevice = () => {
|
|||||||
|
|
||||||
<Row gutter={[20, 0]} style={{ marginTop: '0' }}>
|
<Row gutter={[20, 0]} style={{ marginTop: '0' }}>
|
||||||
<Col xs={24} md={12} lg={12}>
|
<Col xs={24} md={12} lg={12}>
|
||||||
<div
|
<div style={{
|
||||||
style={{
|
|
||||||
padding: '16px',
|
padding: '16px',
|
||||||
border: '1px solid #f0f0f0',
|
border: '1px solid #f0f0f0',
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
backgroundColor: '#ffffff',
|
backgroundColor: '#ffffff',
|
||||||
transition: 'all 0.3s ease',
|
transition: 'all 0.3s ease',
|
||||||
boxShadow: '0 1px 3px rgba(0,0,0,0.04)',
|
boxShadow: '0 1px 3px rgba(0,0,0,0.04)'
|
||||||
}}
|
}}>
|
||||||
>
|
<div style={{
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: '8px',
|
gap: '8px',
|
||||||
marginBottom: '12px',
|
marginBottom: '12px',
|
||||||
paddingBottom: '8px',
|
paddingBottom: '8px',
|
||||||
borderBottom: '1px solid #f5f5f5',
|
borderBottom: '1px solid #f5f5f5'
|
||||||
}}
|
}}>
|
||||||
>
|
<div style={{
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: '3px',
|
width: '3px',
|
||||||
height: '16px',
|
height: '16px',
|
||||||
backgroundColor: '#1890ff',
|
backgroundColor: '#1890ff',
|
||||||
borderRadius: '2px',
|
borderRadius: '2px'
|
||||||
}}
|
}}></div>
|
||||||
></div>
|
<h4 style={{ margin: 0, color: '#262626', fontSize: '14px', fontWeight: '600' }}>
|
||||||
<h4
|
|
||||||
style={{
|
|
||||||
margin: 0,
|
|
||||||
color: '#262626',
|
|
||||||
fontSize: '14px',
|
|
||||||
fontWeight: '600',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Solution
|
Solution
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
@@ -807,23 +756,14 @@ const AddBrandDevice = () => {
|
|||||||
solutionTypes={solutionTypes}
|
solutionTypes={solutionTypes}
|
||||||
solutionStatuses={solutionStatuses}
|
solutionStatuses={solutionStatuses}
|
||||||
onAddSolutionField={handleAddSolutionField}
|
onAddSolutionField={handleAddSolutionField}
|
||||||
onRemoveSolutionField={
|
onRemoveSolutionField={handleRemoveSolutionField}
|
||||||
handleRemoveSolutionField
|
|
||||||
}
|
|
||||||
onSolutionTypeChange={handleSolutionTypeChange}
|
onSolutionTypeChange={handleSolutionTypeChange}
|
||||||
onSolutionStatusChange={
|
onSolutionStatusChange={handleSolutionStatusChange}
|
||||||
handleSolutionStatusChange
|
onSolutionFileUpload={(fileData) => {
|
||||||
}
|
}}
|
||||||
onSolutionFileUpload={(fileData) => {}}
|
|
||||||
onFileView={(fileData) => {
|
onFileView={(fileData) => {
|
||||||
if (
|
if (fileData && (fileData.url || fileData.uploadPath)) {
|
||||||
fileData &&
|
window.open(fileData.url || fileData.uploadPath, '_blank');
|
||||||
(fileData.url || fileData.uploadPath)
|
|
||||||
) {
|
|
||||||
window.open(
|
|
||||||
fileData.url || fileData.uploadPath,
|
|
||||||
'_blank'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
isReadOnly={false}
|
isReadOnly={false}
|
||||||
@@ -832,55 +772,40 @@ const AddBrandDevice = () => {
|
|||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} md={12} lg={12}>
|
<Col xs={24} md={12} lg={12}>
|
||||||
<div
|
<div style={{
|
||||||
style={{
|
|
||||||
padding: '16px',
|
padding: '16px',
|
||||||
border: '1px solid #f0f0f0',
|
border: '1px solid #f0f0f0',
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
backgroundColor: '#ffffff',
|
backgroundColor: '#ffffff',
|
||||||
transition: 'all 0.3s ease',
|
transition: 'all 0.3s ease',
|
||||||
boxShadow: '0 1px 3px rgba(0,0,0,0.04)',
|
boxShadow: '0 1px 3px rgba(0,0,0,0.04)'
|
||||||
}}
|
}}>
|
||||||
>
|
<div style={{
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: '8px',
|
gap: '8px',
|
||||||
marginBottom: '12px',
|
marginBottom: '12px',
|
||||||
paddingBottom: '8px',
|
paddingBottom: '8px',
|
||||||
borderBottom: '1px solid #f5f5f5',
|
borderBottom: '1px solid #f5f5f5'
|
||||||
}}
|
}}>
|
||||||
>
|
<div style={{
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: '3px',
|
width: '3px',
|
||||||
height: '16px',
|
height: '16px',
|
||||||
backgroundColor: '#faad14',
|
backgroundColor: '#faad14',
|
||||||
borderRadius: '2px',
|
borderRadius: '2px'
|
||||||
}}
|
}}></div>
|
||||||
></div>
|
<h4 style={{ margin: 0, color: '#262626', fontSize: '14px', fontWeight: '600' }}>
|
||||||
<h4
|
|
||||||
style={{
|
|
||||||
margin: 0,
|
|
||||||
color: '#262626',
|
|
||||||
fontSize: '14px',
|
|
||||||
fontWeight: '600',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Sparepart Selection
|
Sparepart Selection
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div style={{
|
||||||
style={{
|
|
||||||
maxHeight: '45vh',
|
maxHeight: '45vh',
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
border: '1px solid #e8e8e8',
|
border: '1px solid #e8e8e8',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
padding: '12px',
|
padding: '12px',
|
||||||
backgroundColor: '#fafafa',
|
backgroundColor: '#fafafa'
|
||||||
}}
|
}}>
|
||||||
>
|
|
||||||
<SparepartSelect
|
<SparepartSelect
|
||||||
selectedSparepartIds={selectedSparepartIds}
|
selectedSparepartIds={selectedSparepartIds}
|
||||||
onSparepartChange={setSelectedSparepartIds}
|
onSparepartChange={setSelectedSparepartIds}
|
||||||
@@ -891,16 +816,15 @@ const AddBrandDevice = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<div
|
<div style={{
|
||||||
style={{
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: '16px 0 0 0',
|
padding: '16px 0 0 0',
|
||||||
borderTop: '1px solid #f0f0f0',
|
borderTop: '1px solid #f0f0f0',
|
||||||
marginTop: '12px',
|
marginTop: '12px'
|
||||||
}}
|
}}>
|
||||||
>
|
|
||||||
{editingErrorCodeKey && (
|
{editingErrorCodeKey && (
|
||||||
<Button
|
<Button
|
||||||
size="large"
|
size="large"
|
||||||
@@ -913,7 +837,7 @@ const AddBrandDevice = () => {
|
|||||||
height: '40px',
|
height: '40px',
|
||||||
padding: '0 24px',
|
padding: '0 24px',
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
transition: 'all 0.3s ease',
|
transition: 'all 0.3s ease'
|
||||||
}}
|
}}
|
||||||
onMouseEnter={(e) => {
|
onMouseEnter={(e) => {
|
||||||
e.target.style.borderColor = '#ff4d4f';
|
e.target.style.borderColor = '#ff4d4f';
|
||||||
@@ -947,7 +871,7 @@ const AddBrandDevice = () => {
|
|||||||
|
|
||||||
setBreadcrumbItems([
|
setBreadcrumbItems([
|
||||||
{
|
{
|
||||||
title: <span style={{ fontSize: '14px', fontWeight: 'bold' }}>• Master</span>,
|
title: <span style={{ fontSize: '14px', fontWeight: 'bold' }}>• Master</span>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: (
|
title: (
|
||||||
@@ -971,11 +895,12 @@ const AddBrandDevice = () => {
|
|||||||
if (location.state?.fromFileViewer && location.state.phase !== undefined) {
|
if (location.state?.fromFileViewer && location.state.phase !== undefined) {
|
||||||
setCurrentStep(location.state.phase);
|
setCurrentStep(location.state.phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [setBreadcrumbItems, navigate, searchParams, location.state]);
|
}, [setBreadcrumbItems, navigate, searchParams, location.state]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (brandInfo.brand_id && currentStep === 1) {
|
if (brandInfo.brand_id && currentStep === 1) {
|
||||||
setTrigerFilter((prev) => !prev);
|
setTrigerFilter(prev => !prev);
|
||||||
}
|
}
|
||||||
}, [brandInfo.brand_id, currentStep]);
|
}, [brandInfo.brand_id, currentStep]);
|
||||||
|
|
||||||
@@ -988,7 +913,8 @@ const AddBrandDevice = () => {
|
|||||||
const errorCodes = response.data || [];
|
const errorCodes = response.data || [];
|
||||||
setApiErrorCodes(errorCodes);
|
setApiErrorCodes(errorCodes);
|
||||||
}
|
}
|
||||||
} catch (error) {}
|
} catch (error) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fetchErrorCodes();
|
fetchErrorCodes();
|
||||||
@@ -999,7 +925,8 @@ const AddBrandDevice = () => {
|
|||||||
if (isTemporaryBrand && temporaryBrandId && currentStep === 0) {
|
if (isTemporaryBrand && temporaryBrandId && currentStep === 0) {
|
||||||
try {
|
try {
|
||||||
await deleteBrand(temporaryBrandId);
|
await deleteBrand(temporaryBrandId);
|
||||||
} catch (error) {}
|
} catch (error) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1010,6 +937,7 @@ const AddBrandDevice = () => {
|
|||||||
};
|
};
|
||||||
}, [isTemporaryBrand, temporaryBrandId, currentStep]);
|
}, [isTemporaryBrand, temporaryBrandId, currentStep]);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfigProvider
|
<ConfigProvider
|
||||||
theme={{
|
theme={{
|
||||||
@@ -1060,9 +988,14 @@ const AddBrandDevice = () => {
|
|||||||
<Divider />
|
<Divider />
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||||
<div>
|
<div>
|
||||||
<Button onClick={handleCancel}>Cancel</Button>
|
<Button onClick={handleCancel}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
{currentStep === 1 && (
|
{currentStep === 1 && (
|
||||||
<Button onClick={handlePrevStep} style={{ marginLeft: 8 }}>
|
<Button
|
||||||
|
onClick={handlePrevStep}
|
||||||
|
style={{ marginLeft: 8 }}
|
||||||
|
>
|
||||||
Kembali ke Brand Info
|
Kembali ke Brand Info
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -479,14 +479,14 @@ const EditBrandDevice = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (!solutionData || solutionData.length === 0) {
|
if (!solutionData || solutionData.length === 0) {
|
||||||
// NotifAlert({
|
NotifAlert({
|
||||||
// icon: 'warning',
|
icon: 'warning',
|
||||||
// title: 'Perhatian',
|
title: 'Perhatian',
|
||||||
// message: 'Setiap error code harus memiliki minimal 1 solution!',
|
message: 'Setiap error code harus memiliki minimal 1 solution!',
|
||||||
// });
|
});
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
const formattedSolutions = solutionData.map(solution => {
|
const formattedSolutions = solutionData.map(solution => {
|
||||||
const solutionType = solution.type || 'text';
|
const solutionType = solution.type || 'text';
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
import React, { useState, useEffect, useMemo } from 'react';
|
import React, { useState, useEffect, useMemo } from 'react';
|
||||||
import { Card, Input, Button, Row, Col, Empty } from 'antd';
|
import { Card, Input, Button, Row, Col, Empty } from 'antd';
|
||||||
import {
|
import { PlusOutlined, SearchOutlined, DeleteOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons';
|
||||||
PlusOutlined,
|
|
||||||
SearchOutlined,
|
|
||||||
DeleteOutlined,
|
|
||||||
LeftOutlined,
|
|
||||||
RightOutlined,
|
|
||||||
} from '@ant-design/icons';
|
|
||||||
import { getErrorCodesByBrandId, deleteErrorCode } from '../../../../api/master-brand';
|
import { getErrorCodesByBrandId, deleteErrorCode } from '../../../../api/master-brand';
|
||||||
import { NotifAlert, NotifOk, NotifConfirmDialog } from '../../../../components/Global/ToastNotif';
|
import { NotifAlert, NotifOk, NotifConfirmDialog } from '../../../../components/Global/ToastNotif';
|
||||||
|
|
||||||
@@ -22,7 +16,7 @@ const ListErrorCode = ({
|
|||||||
onSearch,
|
onSearch,
|
||||||
onSearchClear,
|
onSearchClear,
|
||||||
isReadOnly = false,
|
isReadOnly = false,
|
||||||
errorCodes: propErrorCodes = null,
|
errorCodes: propErrorCodes = null
|
||||||
}) => {
|
}) => {
|
||||||
const [errorCodes, setErrorCodes] = useState([]);
|
const [errorCodes, setErrorCodes] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -58,12 +52,12 @@ const ListErrorCode = ({
|
|||||||
if (response && response.statusCode === 200) {
|
if (response && response.statusCode === 200) {
|
||||||
const apiErrorData = response.data || [];
|
const apiErrorData = response.data || [];
|
||||||
const allErrorCodes = [
|
const allErrorCodes = [
|
||||||
...apiErrorData.map((ec) => ({
|
...apiErrorData.map(ec => ({
|
||||||
...ec,
|
...ec,
|
||||||
tempId: `existing_${ec.error_code_id}`,
|
tempId: `existing_${ec.error_code_id}`,
|
||||||
status: 'existing',
|
status: 'existing'
|
||||||
})),
|
})),
|
||||||
...tempErrorCodes.filter((ec) => ec.status !== 'deleted'),
|
...tempErrorCodes.filter(ec => ec.status !== 'deleted')
|
||||||
];
|
];
|
||||||
|
|
||||||
setErrorCodes(allErrorCodes);
|
setErrorCodes(allErrorCodes);
|
||||||
@@ -88,9 +82,11 @@ const ListErrorCode = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isReadOnly && propErrorCodes) {
|
if (isReadOnly && propErrorCodes) {
|
||||||
|
|
||||||
setErrorCodes(propErrorCodes);
|
setErrorCodes(propErrorCodes);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
fetchErrorCodes();
|
fetchErrorCodes();
|
||||||
}
|
}
|
||||||
}, [brandId, queryParams, tempErrorCodes, trigerFilter, isReadOnly, propErrorCodes]);
|
}, [brandId, queryParams, tempErrorCodes, trigerFilter, isReadOnly, propErrorCodes]);
|
||||||
@@ -131,18 +127,19 @@ const ListErrorCode = ({
|
|||||||
message: `Apakah Anda yakin ingin menghapus error code ${item.error_code}?`,
|
message: `Apakah Anda yakin ingin menghapus error code ${item.error_code}?`,
|
||||||
onConfirm: () => performDelete(item),
|
onConfirm: () => performDelete(item),
|
||||||
onCancel: () => { },
|
onCancel: () => { },
|
||||||
confirmButtonText: 'Hapus',
|
confirmButtonText: 'Hapus'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const performDelete = async (item) => {
|
const performDelete = async (item) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (!item.error_code_id || item.error_code_id === 'undefined') {
|
if (!item.error_code_id || item.error_code_id === 'undefined') {
|
||||||
NotifAlert({
|
NotifAlert({
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
message: 'Error code ID tidak valid',
|
message: 'Error code ID tidak valid'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -151,7 +148,7 @@ const ListErrorCode = ({
|
|||||||
NotifAlert({
|
NotifAlert({
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
message: 'Brand ID tidak valid',
|
message: 'Brand ID tidak valid'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -162,21 +159,21 @@ const ListErrorCode = ({
|
|||||||
NotifOk({
|
NotifOk({
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
title: 'Berhasil',
|
title: 'Berhasil',
|
||||||
message: 'Error code berhasil dihapus',
|
message: 'Error code berhasil dihapus'
|
||||||
});
|
});
|
||||||
fetchErrorCodes();
|
fetchErrorCodes();
|
||||||
} else {
|
} else {
|
||||||
NotifAlert({
|
NotifAlert({
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
title: 'Gagal',
|
title: 'Gagal',
|
||||||
message: 'Gagal menghapus error code',
|
message: 'Gagal menghapus error code'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
NotifAlert({
|
NotifAlert({
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
message: 'Terjadi kesalahan saat menghapus error code',
|
message: 'Terjadi kesalahan saat menghapus error code'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -184,8 +181,8 @@ const ListErrorCode = ({
|
|||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title="Daftar Error Code"
|
title="Daftar Error Code"
|
||||||
style={{ width: '100%', minWidth: '300px' }}
|
style={{ width: '100%', minWidth: '472px' }}
|
||||||
bodyStyle={{ padding: '12px' }}
|
styles={{ body: { padding: '12px' } }}
|
||||||
>
|
>
|
||||||
<Input.Search
|
<Input.Search
|
||||||
placeholder="Cari error code..."
|
placeholder="Cari error code..."
|
||||||
@@ -206,7 +203,7 @@ const ListErrorCode = ({
|
|||||||
style={{
|
style={{
|
||||||
backgroundColor: '#23A55A',
|
backgroundColor: '#23A55A',
|
||||||
borderColor: '#23A55A',
|
borderColor: '#23A55A',
|
||||||
height: '32px',
|
height: '32px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Search
|
Search
|
||||||
@@ -220,18 +217,19 @@ const ListErrorCode = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div style={{
|
||||||
style={{
|
|
||||||
height: '90vh',
|
height: '90vh',
|
||||||
border: '1px solid #d9d9d9',
|
border: '1px solid #d9d9d9',
|
||||||
borderRadius: '6px',
|
borderRadius: '6px',
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
backgroundColor: '#fafafa',
|
backgroundColor: '#fafafa'
|
||||||
}}
|
}}>
|
||||||
>
|
|
||||||
{errorCodes.length === 0 ? (
|
{errorCodes.length === 0 ? (
|
||||||
<Empty description="Belum ada error code" style={{ marginTop: 50 }} />
|
<Empty
|
||||||
|
description="Belum ada error code"
|
||||||
|
style={{ marginTop: 50 }}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ padding: '8px' }}>
|
<div style={{ padding: '8px' }}>
|
||||||
{errorCodes.map((item) => (
|
{errorCodes.map((item) => (
|
||||||
@@ -242,25 +240,13 @@ const ListErrorCode = ({
|
|||||||
padding: '8px 12px',
|
padding: '8px 12px',
|
||||||
borderRadius: '6px',
|
borderRadius: '6px',
|
||||||
marginBottom: '4px',
|
marginBottom: '4px',
|
||||||
border:
|
border: selectedErrorCode?.tempId === item.tempId ? '2px solid #23A55A' : '1px solid #d9d9d9',
|
||||||
selectedErrorCode?.tempId === item.tempId
|
backgroundColor: selectedErrorCode?.tempId === item.tempId ? '#f6ffed' : '#fff',
|
||||||
? '2px solid #23A55A'
|
transition: 'all 0.2s ease'
|
||||||
: '1px solid #d9d9d9',
|
|
||||||
backgroundColor:
|
|
||||||
selectedErrorCode?.tempId === item.tempId
|
|
||||||
? '#f6ffed'
|
|
||||||
: '#fff',
|
|
||||||
transition: 'all 0.2s ease',
|
|
||||||
}}
|
}}
|
||||||
onClick={() => onErrorCodeSelect(item)}
|
onClick={() => onErrorCodeSelect(item)}
|
||||||
>
|
>
|
||||||
<div
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<div style={{ fontWeight: 'bold', fontSize: '12px' }}>
|
<div style={{ fontWeight: 'bold', fontSize: '12px' }}>
|
||||||
{item.error_code}
|
{item.error_code}
|
||||||
@@ -280,7 +266,7 @@ const ListErrorCode = ({
|
|||||||
padding: '2px 6px',
|
padding: '2px 6px',
|
||||||
height: '24px',
|
height: '24px',
|
||||||
fontSize: '11px',
|
fontSize: '11px',
|
||||||
border: '1px solid #ff4d4f',
|
border: '1px solid #ff4d4f'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -306,15 +292,9 @@ const ListErrorCode = ({
|
|||||||
onClick={handlePrevious}
|
onClick={handlePrevious}
|
||||||
disabled={pagination.current_page <= 1}
|
disabled={pagination.current_page <= 1}
|
||||||
size="small"
|
size="small"
|
||||||
></Button>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: '12px',
|
|
||||||
color: '#666',
|
|
||||||
minWidth: '60px',
|
|
||||||
textAlign: 'center',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
|
</Button>
|
||||||
|
<span style={{ fontSize: '12px', color: '#666', minWidth: '60px', textAlign: 'center' }}>
|
||||||
{pagination.current_page} / {pagination.total_page}
|
{pagination.current_page} / {pagination.total_page}
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<Button
|
||||||
@@ -322,7 +302,8 @@ const ListErrorCode = ({
|
|||||||
onClick={handleNext}
|
onClick={handleNext}
|
||||||
disabled={pagination.current_page >= pagination.total_page}
|
disabled={pagination.current_page >= pagination.total_page}
|
||||||
size="small"
|
size="small"
|
||||||
></Button>
|
>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const DetailPlantSubSection = (props) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log(`📝 Input change: ${name} = ${value}`);
|
console.log(`📝 Input change: ${name} = ${value}`);
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
setFormData((prev) => ({
|
setFormData((prev) => ({
|
||||||
@@ -74,20 +74,16 @@ const DetailPlantSubSection = (props) => {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// console.log('💾 Current formData before save:', formData);
|
console.log('💾 Current formData before save:', formData);
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
plant_sub_section_name: formData.plant_sub_section_name,
|
plant_sub_section_name: formData.plant_sub_section_name,
|
||||||
plant_sub_section_description:
|
plant_sub_section_description: (formData.plant_sub_section_description && formData.plant_sub_section_description.trim() !== '') ? formData.plant_sub_section_description : ' ',
|
||||||
formData.plant_sub_section_description &&
|
|
||||||
formData.plant_sub_section_description.trim() !== ''
|
|
||||||
? formData.plant_sub_section_description
|
|
||||||
: ' ',
|
|
||||||
table_name_value: formData.table_name_value, // Fix field name
|
table_name_value: formData.table_name_value, // Fix field name
|
||||||
is_active: formData.is_active,
|
is_active: formData.is_active,
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log('📤 Payload to be sent:', payload);
|
console.log('📤 Payload to be sent:', payload);
|
||||||
|
|
||||||
const response =
|
const response =
|
||||||
props.actionMode === 'edit'
|
props.actionMode === 'edit'
|
||||||
@@ -130,17 +126,17 @@ const DetailPlantSubSection = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// console.log('🔄 Modal state changed:', {
|
console.log('🔄 Modal state changed:', {
|
||||||
// showModal: props.showModal,
|
showModal: props.showModal,
|
||||||
// actionMode: props.actionMode,
|
actionMode: props.actionMode,
|
||||||
// selectedData: props.selectedData,
|
selectedData: props.selectedData,
|
||||||
// });
|
});
|
||||||
|
|
||||||
if (props.selectedData) {
|
if (props.selectedData) {
|
||||||
// console.log('📋 Setting form data from selectedData:', props.selectedData);
|
console.log('📋 Setting form data from selectedData:', props.selectedData);
|
||||||
setFormData(props.selectedData);
|
setFormData(props.selectedData);
|
||||||
} else {
|
} else {
|
||||||
// console.log('📋 Resetting to default data');
|
console.log('📋 Resetting to default data');
|
||||||
setFormData(defaultData);
|
setFormData(defaultData);
|
||||||
}
|
}
|
||||||
}, [props.showModal, props.selectedData, props.actionMode]);
|
}, [props.showModal, props.selectedData, props.actionMode]);
|
||||||
|
|||||||
@@ -112,9 +112,9 @@ const DetailShift = (props) => {
|
|||||||
is_active: formData.is_active,
|
is_active: formData.is_active,
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log('Payload yang dikirim:', payload);
|
console.log('Payload yang dikirim:', payload);
|
||||||
// console.log('Type start_time:', typeof payload.start_time, payload.start_time);
|
console.log('Type start_time:', typeof payload.start_time, payload.start_time);
|
||||||
// console.log('Type end_time:', typeof payload.end_time, payload.end_time);
|
console.log('Type end_time:', typeof payload.end_time, payload.end_time);
|
||||||
|
|
||||||
const response =
|
const response =
|
||||||
props.actionMode === 'edit'
|
props.actionMode === 'edit'
|
||||||
|
|||||||
@@ -95,11 +95,11 @@ const DetailSparepart = (props) => {
|
|||||||
const newFile = fileList.length > 0 ? fileList[0] : null;
|
const newFile = fileList.length > 0 ? fileList[0] : null;
|
||||||
|
|
||||||
if (newFile && newFile.originFileObj) {
|
if (newFile && newFile.originFileObj) {
|
||||||
// console.log('Uploading file:', newFile.originFileObj);
|
console.log('Uploading file:', newFile.originFileObj);
|
||||||
const uploadResponse = await uploadFile(newFile.originFileObj, 'images');
|
const uploadResponse = await uploadFile(newFile.originFileObj, 'images');
|
||||||
|
|
||||||
// Log untuk debugging
|
// Log untuk debugging
|
||||||
// console.log('Upload response:', uploadResponse);
|
console.log('Upload response:', uploadResponse);
|
||||||
|
|
||||||
// Cek berbagai kemungkinan struktur respons dari API
|
// Cek berbagai kemungkinan struktur respons dari API
|
||||||
let uploadedUrl = null;
|
let uploadedUrl = null;
|
||||||
@@ -169,7 +169,7 @@ const DetailSparepart = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (uploadedUrl) {
|
if (uploadedUrl) {
|
||||||
// console.log('Successfully extracted image URL:', uploadedUrl);
|
console.log('Successfully extracted image URL:', uploadedUrl);
|
||||||
imageUrl = uploadedUrl;
|
imageUrl = uploadedUrl;
|
||||||
} else {
|
} else {
|
||||||
console.error('Upload response structure:', uploadResponse);
|
console.error('Upload response structure:', uploadResponse);
|
||||||
@@ -209,10 +209,7 @@ const DetailSparepart = (props) => {
|
|||||||
sparepart_name: formData.sparepart_name, // Wajib
|
sparepart_name: formData.sparepart_name, // Wajib
|
||||||
};
|
};
|
||||||
|
|
||||||
payload.sparepart_description =
|
payload.sparepart_description = (formData.sparepart_description && formData.sparepart_description.trim() !== '') ? formData.sparepart_description : ' ';
|
||||||
formData.sparepart_description && formData.sparepart_description.trim() !== ''
|
|
||||||
? formData.sparepart_description
|
|
||||||
: ' ';
|
|
||||||
if (formData.sparepart_model && formData.sparepart_model.trim() !== '') {
|
if (formData.sparepart_model && formData.sparepart_model.trim() !== '') {
|
||||||
payload.sparepart_model = formData.sparepart_model;
|
payload.sparepart_model = formData.sparepart_model;
|
||||||
}
|
}
|
||||||
@@ -236,13 +233,13 @@ const DetailSparepart = (props) => {
|
|||||||
payload.sparepart_foto = imageUrl;
|
payload.sparepart_foto = imageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('Sending payload:', payload);
|
console.log('Sending payload:', payload);
|
||||||
|
|
||||||
const response = formData.sparepart_id
|
const response = formData.sparepart_id
|
||||||
? await updateSparepart(formData.sparepart_id, payload)
|
? await updateSparepart(formData.sparepart_id, payload)
|
||||||
: await createSparepart(payload);
|
: await createSparepart(payload);
|
||||||
|
|
||||||
// console.log('API response:', response);
|
console.log('API response:', response);
|
||||||
|
|
||||||
if (response && (response.statusCode === 200 || response.statusCode === 201)) {
|
if (response && (response.statusCode === 200 || response.statusCode === 201)) {
|
||||||
NotifOk({
|
NotifOk({
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ const ListUnit = memo(function ListUnit(props) {
|
|||||||
const handleDelete = async (param) => {
|
const handleDelete = async (param) => {
|
||||||
try {
|
try {
|
||||||
const response = await deleteUnit(param.unit_id);
|
const response = await deleteUnit(param.unit_id);
|
||||||
// console.log('deleteUnit response:', response);
|
console.log('deleteUnit response:', response);
|
||||||
|
|
||||||
if (response.statusCode === 200) {
|
if (response.statusCode === 200) {
|
||||||
NotifAlert({
|
NotifAlert({
|
||||||
|
|||||||
@@ -38,35 +38,16 @@ import {
|
|||||||
SearchOutlined,
|
SearchOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { useNavigate, Link as RouterLink } from 'react-router-dom';
|
import { useNavigate, Link as RouterLink } from 'react-router-dom';
|
||||||
import {
|
import { getAllNotification, getNotificationLogByNotificationId } from '../../../api/notification';
|
||||||
getAllNotification,
|
|
||||||
getNotificationLogByNotificationId,
|
|
||||||
getNotificationDetail,
|
|
||||||
resendChatByUser,
|
|
||||||
resendChatAllUser,
|
|
||||||
searchData,
|
|
||||||
} from '../../../api/notification';
|
|
||||||
import { onNotifUpdate } from '../../../components/Global/MqttConnection';
|
|
||||||
|
|
||||||
const { Text, Paragraph, Link: AntdLink } = Typography;
|
const { Text, Paragraph, Link: AntdLink } = Typography;
|
||||||
const OpenMail = ({ size = 22, color = 'black' }) => (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 640 640"
|
|
||||||
width={size}
|
|
||||||
height={size}
|
|
||||||
fill={color}
|
|
||||||
>
|
|
||||||
<path d="M576 480C576 515.3 547.5 544 512.1 544L128 544C92.6 544 64 515.3 64 480L64 228C64.1 212.5 71.8 198 84.5 189.2L270 61.3C300.1 40.6 339.8 40.6 369.9 61.3L555.5 189.2C568.3 198 575.9 212.5 576 228L576 480zM128 496L512.1 496C520.9 496 528 488.9 528 480L528 288.3L373.2 405.7C341.8 429.6 298.3 429.6 266.8 405.7L112 288.3L112 480C112 488.9 119.2 496 128 496zM527.6 228.4L342.7 100.8C329 91.4 311 91.4 297.3 100.8L112.4 228.4L295.8 367.5C310.1 378.3 329.9 378.3 344.2 367.5L527.6 228.4z" />
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
// Transform API response to component format
|
// Transform API response to component format
|
||||||
const transformNotificationData = (apiData) => {
|
const transformNotificationData = (apiData) => {
|
||||||
return apiData.map((item, index) => ({
|
return apiData.map((item, index) => ({
|
||||||
id: `notification-${item.notification_error_id}-${index}`, // Unique key prefix with array index
|
id: `notification-${item.notification_error_id}-${index}`, // Unique key prefix with array index
|
||||||
type: item.is_read ? 'resolved' : item.is_delivered ? 'warning' : 'critical',
|
type: item.is_read ? 'resolved' : item.is_delivered ? 'warning' : 'critical',
|
||||||
title: item.error_code_name || 'Unknown Error',
|
title: item.error_code_name || 'Unknown Error',
|
||||||
color: item.error_code_color || 'Black',
|
|
||||||
issue: item.error_code || item.error_code_name || 'Unknown Error',
|
issue: item.error_code || item.error_code_name || 'Unknown Error',
|
||||||
description: `${item.error_code} - ${item.error_code_name || ''}`,
|
description: `${item.error_code} - ${item.error_code_name || ''}`,
|
||||||
timestamp: item.created_at
|
timestamp: item.created_at
|
||||||
@@ -79,8 +60,7 @@ const transformNotificationData = (apiData) => {
|
|||||||
}) + ' WIB'
|
}) + ' WIB'
|
||||||
: 'N/A',
|
: 'N/A',
|
||||||
location: item.plant_sub_section_name || item.device_location || 'Location not specified',
|
location: item.plant_sub_section_name || item.device_location || 'Location not specified',
|
||||||
details: item.device_name || '-',
|
details: item.message_error_issue || 'No details available',
|
||||||
errId: item.notification_error_id || 0,
|
|
||||||
link: `/verification-sparepart/${item.notification_error_id}`, // Dummy URL untuk verifikasi spare part
|
link: `/verification-sparepart/${item.notification_error_id}`, // Dummy URL untuk verifikasi spare part
|
||||||
subsection: item.plant_sub_section_name || 'N/A',
|
subsection: item.plant_sub_section_name || 'N/A',
|
||||||
isRead: item.is_read,
|
isRead: item.is_read,
|
||||||
@@ -97,20 +77,42 @@ const transformNotificationData = (apiData) => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Dummy data untuk user history
|
||||||
|
const userHistoryData = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
name: 'John Doe',
|
||||||
|
phone: '081234567890',
|
||||||
|
status: 'Delivered',
|
||||||
|
timestamp: '04-11-2025 11:40 WIB',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
name: 'Jane Smith',
|
||||||
|
phone: '087654321098',
|
||||||
|
status: 'Delivered',
|
||||||
|
timestamp: '04-11-2025 11:41 WIB',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
name: 'Peter Jones',
|
||||||
|
phone: '082345678901',
|
||||||
|
status: 'Delivered',
|
||||||
|
timestamp: '04-11-2025 11:42 WIB',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const ListNotification = memo(function ListNotification(props) {
|
const ListNotification = memo(function ListNotification(props) {
|
||||||
const [notifications, setNotifications] = useState([]);
|
const [notifications, setNotifications] = useState([]);
|
||||||
const [activeTab, setActiveTab] = useState('all');
|
const [activeTab, setActiveTab] = useState('all');
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [notifTrigger, setNotifTrigger] = useState(0);
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [modalContent, setModalContent] = useState(null); // 'user', 'log', 'details', or null
|
const [modalContent, setModalContent] = useState(null); // 'user', 'log', 'details', or null
|
||||||
const [isAddingLog, setIsAddingLog] = useState(false);
|
const [isAddingLog, setIsAddingLog] = useState(false);
|
||||||
const [selectedNotification, setSelectedNotification] = useState(null);
|
const [selectedNotification, setSelectedNotification] = useState(null);
|
||||||
const [logHistoryData, setLogHistoryData] = useState([]);
|
const [logHistoryData, setLogHistoryData] = useState([]);
|
||||||
const [logLoading, setLogLoading] = useState(false);
|
const [logLoading, setLogLoading] = useState(false);
|
||||||
const [userHistoryData, setUserHistoryData] = useState([]);
|
|
||||||
const [userLoading, setUserLoading] = useState(false);
|
|
||||||
const [pagination, setPagination] = useState({
|
const [pagination, setPagination] = useState({
|
||||||
current_page: 1,
|
current_page: 1,
|
||||||
current_limit: 10,
|
current_limit: 10,
|
||||||
@@ -180,12 +182,6 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
fetchNotifications(page, pageSize, isReadFilter);
|
fetchNotifications(page, pageSize, isReadFilter);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
onNotifUpdate(() => {
|
|
||||||
setNotifTrigger((prev) => prev + 1);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@@ -196,18 +192,18 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
// Fetch notifications on component mount and when tab changes
|
// Fetch notifications on component mount and when tab changes
|
||||||
const isReadFilter = activeTab === 'read' ? 1 : activeTab === 'unread' ? 0 : null;
|
const isReadFilter = activeTab === 'read' ? 1 : activeTab === 'unread' ? 0 : null;
|
||||||
fetchNotifications(pagination.current_page, pagination.current_limit, isReadFilter);
|
fetchNotifications(pagination.current_page, pagination.current_limit, isReadFilter);
|
||||||
}, [activeTab, notifTrigger]);
|
}, [activeTab]);
|
||||||
|
|
||||||
const getIconAndColor = (type) => {
|
const getIconAndColor = (type) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'critical':
|
case 'critical':
|
||||||
return { IconComponent: MailOutlined, color: '#faad14', bgColor: '#fff1f0' };
|
return { IconComponent: CloseCircleFilled, color: '#ff4d4f', bgColor: '#fff1f0' };
|
||||||
case 'warning':
|
case 'warning':
|
||||||
return { IconComponent: MailOutlined, color: '#1890ff', bgColor: '#fffbe6' };
|
return { IconComponent: WarningFilled, color: '#faad14', bgColor: '#fffbe6' };
|
||||||
case 'resolved':
|
case 'resolved':
|
||||||
return { IconComponent: MailOutlined, color: '#52c41a', bgColor: '#f6ffed' };
|
return { IconComponent: CheckCircleFilled, color: '#52c41a', bgColor: '#f6ffed' };
|
||||||
default:
|
default:
|
||||||
return { IconComponent: MailOutlined, color: '#1890ff', bgColor: '#e6f7ff' };
|
return { IconComponent: InfoCircleFilled, color: '#1890ff', bgColor: '#e6f7ff' };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -218,9 +214,9 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
content: `Are you sure you want to resend the notification for "${notification.title}"?`,
|
content: `Are you sure you want to resend the notification for "${notification.title}"?`,
|
||||||
okText: 'Resend',
|
okText: 'Resend',
|
||||||
cancelText: 'Cancel',
|
cancelText: 'Cancel',
|
||||||
async onOk() {
|
onOk() {
|
||||||
console.log('Resending notification:', notification.id);
|
console.log('Resending notification:', notification.id);
|
||||||
await resendChatAllUser(notification.errId);
|
|
||||||
message.success(
|
message.success(
|
||||||
`Notification for "${notification.title}" has been resent successfully.`
|
`Notification for "${notification.title}" has been resent successfully.`
|
||||||
);
|
);
|
||||||
@@ -239,49 +235,13 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchSearch = async (data) => {
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const response = await searchData(data);
|
|
||||||
if (response && response.data) {
|
|
||||||
const transformedData = transformNotificationData(response.data);
|
|
||||||
setNotifications(transformedData);
|
|
||||||
|
|
||||||
// Update pagination with API response or calculate from data
|
|
||||||
if (response.paging) {
|
|
||||||
setPagination({
|
|
||||||
current_page: response.paging.current_page || page,
|
|
||||||
current_limit: response.paging.current_limit || limit,
|
|
||||||
total_limit: response.paging.total_limit || transformedData.length,
|
|
||||||
total_page:
|
|
||||||
response.paging.total_page || Math.ceil(transformedData.length / limit),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Fallback: calculate pagination from data
|
|
||||||
const totalItems = transformedData.length;
|
|
||||||
setPagination((prev) => ({
|
|
||||||
...prev,
|
|
||||||
current_page: page,
|
|
||||||
current_limit: limit,
|
|
||||||
total_limit: totalItems,
|
|
||||||
total_page: Math.ceil(totalItems / limit),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
fetchSearch(searchValue);
|
setSearchTerm(searchValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSearchClear = () => {
|
const handleSearchClear = () => {
|
||||||
setSearchValue('');
|
setSearchValue('');
|
||||||
fetchSearch('');
|
setSearchTerm('');
|
||||||
};
|
};
|
||||||
|
|
||||||
const getUnreadCount = () => notifications.filter((n) => !n.isRead).length;
|
const getUnreadCount = () => notifications.filter((n) => !n.isRead).length;
|
||||||
@@ -330,44 +290,6 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fetch user history from API
|
|
||||||
const fetchUserHistory = async (notificationId) => {
|
|
||||||
try {
|
|
||||||
setUserLoading(true);
|
|
||||||
|
|
||||||
const response = await getNotificationDetail(notificationId);
|
|
||||||
|
|
||||||
if (response && response.data && response.data.users) {
|
|
||||||
// Transform API data to component format
|
|
||||||
const transformedUsers = response.data.users.map((user) => ({
|
|
||||||
id: user.notification_error_user_id.toString(),
|
|
||||||
name: user.contact_name,
|
|
||||||
phone: user.contact_phone,
|
|
||||||
status: user.is_send ? 'Delivered' : 'Pending',
|
|
||||||
timestamp: user.updated_at
|
|
||||||
? new Date(user.updated_at)
|
|
||||||
.toLocaleString('id-ID', {
|
|
||||||
day: '2-digit',
|
|
||||||
month: '2-digit',
|
|
||||||
year: 'numeric',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit',
|
|
||||||
})
|
|
||||||
.replace('.', ':') + ' WIB'
|
|
||||||
: 'N/A',
|
|
||||||
}));
|
|
||||||
setUserHistoryData(transformedUsers);
|
|
||||||
} else {
|
|
||||||
setUserHistoryData([]);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error fetching user history:', err);
|
|
||||||
setUserHistoryData([]); // Set empty array on error
|
|
||||||
} finally {
|
|
||||||
setUserLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const tabButtonStyle = (isActive) => ({
|
const tabButtonStyle = (isActive) => ({
|
||||||
padding: '12px 16px',
|
padding: '12px 16px',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
@@ -424,11 +346,7 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{notification.type === 'resolved' ? (
|
|
||||||
<OpenMail size={28.5} color={color} />
|
|
||||||
) : (
|
|
||||||
<IconComponent style={{ fontSize: '22px' }} />
|
<IconComponent style={{ fontSize: '22px' }} />
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<Row align="top">
|
<Row align="top">
|
||||||
@@ -443,12 +361,8 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
<div>
|
<div>
|
||||||
<Text strong>{notification.title}</Text>
|
<Text strong>{notification.title}</Text>
|
||||||
<div style={{ marginTop: '4px' }}>
|
<div style={{ marginTop: '4px' }}>
|
||||||
<Text
|
<Text style={{ color }}>
|
||||||
style={{
|
{notification.issue}
|
||||||
color: notification.color,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Error Code {notification.issue}
|
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -465,7 +379,7 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col flex="auto">
|
<Col flex="auto">
|
||||||
{/* <div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
gap: '8px',
|
gap: '8px',
|
||||||
@@ -488,18 +402,12 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
>
|
>
|
||||||
{notification.details}
|
{notification.details}
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</div> */}
|
</div>
|
||||||
<Space
|
<Space
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
size={4}
|
size={4}
|
||||||
style={{ fontSize: '13px', color: '#8c8c8c' }}
|
style={{ fontSize: '13px', color: '#8c8c8c' }}
|
||||||
>
|
>
|
||||||
<Space>
|
|
||||||
<MobileOutlined />
|
|
||||||
<Text type="secondary">
|
|
||||||
{notification.details}
|
|
||||||
</Text>
|
|
||||||
</Space>
|
|
||||||
<Space>
|
<Space>
|
||||||
<ClockCircleOutlined />
|
<ClockCircleOutlined />
|
||||||
<Text type="secondary">
|
<Text type="secondary">
|
||||||
@@ -513,10 +421,17 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
</Text>
|
</Text>
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
|
<LinkOutlined />
|
||||||
|
<AntdLink
|
||||||
|
href={notification.link}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{notification.link}
|
||||||
|
</AntdLink>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
icon={<SendOutlined />}
|
icon={<SendOutlined />}
|
||||||
style={{ paddingLeft: '0px' }}
|
style={{ paddingLeft: '8px' }}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handleResend(notification);
|
handleResend(notification);
|
||||||
@@ -552,18 +467,8 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
border: '1px solid #1890ff',
|
border: '1px solid #1890ff',
|
||||||
borderRadius: '4px',
|
borderRadius: '4px',
|
||||||
}}
|
}}
|
||||||
onClick={async (e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
setSelectedNotification(notification);
|
|
||||||
|
|
||||||
// Extract notification ID from the notification object
|
|
||||||
const notificationId =
|
|
||||||
notification.id.split('-')[1];
|
|
||||||
|
|
||||||
// Fetch user history for the selected notification
|
|
||||||
await fetchUserHistory(notificationId);
|
|
||||||
|
|
||||||
setModalContent('user');
|
setModalContent('user');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -630,11 +535,6 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
|
|
||||||
const renderUserHistory = () => (
|
const renderUserHistory = () => (
|
||||||
<>
|
<>
|
||||||
{userLoading ? (
|
|
||||||
<div style={{ textAlign: 'center', padding: '24px' }}>
|
|
||||||
<Spin size="large" />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
||||||
{userHistoryData.map((user) => (
|
{userHistoryData.map((user) => (
|
||||||
<Card key={user.id} style={{ borderColor: '#91d5ff' }}>
|
<Card key={user.id} style={{ borderColor: '#91d5ff' }}>
|
||||||
@@ -647,50 +547,25 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
<MobileOutlined /> {user.phone}
|
<MobileOutlined /> {user.phone}
|
||||||
</Text>
|
</Text>
|
||||||
<Text>|</Text>
|
<Text>|</Text>
|
||||||
<Badge
|
<Badge status="success" text={user.status} />
|
||||||
status={
|
|
||||||
user.status === 'Delivered' ? 'success' : 'default'
|
|
||||||
}
|
|
||||||
text={user.status}
|
|
||||||
/>
|
|
||||||
</Space>
|
</Space>
|
||||||
<Divider style={{ margin: '8px 0' }} />
|
<Divider style={{ margin: '8px 0' }} />
|
||||||
<Space align="center">
|
<Space align="center">
|
||||||
{user.status === 'Delivered' ? (
|
|
||||||
<CheckCircleFilled style={{ color: '#52c41a' }} />
|
<CheckCircleFilled style={{ color: '#52c41a' }} />
|
||||||
) : (
|
|
||||||
<ClockCircleOutlined style={{ color: '#faad14' }} />
|
|
||||||
)}
|
|
||||||
<Text type="secondary">
|
<Text type="secondary">
|
||||||
{user.status === 'Delivered'
|
Success Delivered at {user.timestamp}
|
||||||
? 'Success Delivered at'
|
|
||||||
: 'Status '}{' '}
|
|
||||||
{user.timestamp}
|
|
||||||
</Text>
|
</Text>
|
||||||
</Space>
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
<Col>
|
<Col>
|
||||||
<Button
|
<Button type="primary" ghost icon={<SendOutlined />}>
|
||||||
type="primary"
|
|
||||||
ghost
|
|
||||||
icon={<SendOutlined />}
|
|
||||||
onClick={async () => {
|
|
||||||
await resendChatByUser(user.id, user.phone);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Resend
|
Resend
|
||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
{userHistoryData.length === 0 && (
|
|
||||||
<div style={{ textAlign: 'center', padding: '24px', color: '#8c8c8c' }}>
|
|
||||||
No user history available
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Space>
|
</Space>
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -705,17 +580,7 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
Tidak ada log history
|
Tidak ada log history
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div style={{ padding: '0 16px', position: 'relative' }}>
|
||||||
style={{
|
|
||||||
height: '400px',
|
|
||||||
overflowY: 'auto',
|
|
||||||
padding: '0 16px',
|
|
||||||
position: 'relative',
|
|
||||||
border: '1px solid #f0f0f0',
|
|
||||||
borderRadius: '4px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ position: 'relative' }}>
|
|
||||||
{/* Garis vertikal yang menyambung */}
|
{/* Garis vertikal yang menyambung */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -761,8 +626,8 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
{/* Kolom Kanan: Card */}
|
{/* Kolom Kanan: Card */}
|
||||||
<Col flex="auto">
|
<Col flex="auto">
|
||||||
<Card size="small" style={{ borderColor: '#91d5ff' }}>
|
<Card size="small" style={{ borderColor: '#91d5ff' }}>
|
||||||
<Row gutter={[16, 8]} align="top">
|
<Row gutter={[16, 8]} align="middle">
|
||||||
<Col xs={24} md={10}>
|
<Col xs={24} md={12}>
|
||||||
<Space direction="vertical" size={4}>
|
<Space direction="vertical" size={4}>
|
||||||
<Space>
|
<Space>
|
||||||
<ClockCircleOutlined />
|
<ClockCircleOutlined />
|
||||||
@@ -773,14 +638,11 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
Added at {log.timestamp}
|
Added at {log.timestamp}
|
||||||
</Text>
|
</Text>
|
||||||
</Space>
|
</Space>
|
||||||
|
|
||||||
<div>
|
|
||||||
<Text strong>{log.addedBy.name}</Text>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
<Text strong>Added by: {log.addedBy.name}</Text>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
|
marginLeft: '8px',
|
||||||
border: '1px solid #52c41a',
|
border: '1px solid #52c41a',
|
||||||
color: '#52c41a',
|
color: '#52c41a',
|
||||||
padding: '2px 6px',
|
padding: '2px 6px',
|
||||||
@@ -793,8 +655,7 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
</div>
|
</div>
|
||||||
</Space>
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} md={14}>
|
<Col xs={24} md={12}>
|
||||||
<Text strong>Description:</Text>
|
|
||||||
<Paragraph
|
<Paragraph
|
||||||
style={{
|
style={{
|
||||||
color: '#595959',
|
color: '#595959',
|
||||||
@@ -811,7 +672,6 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
</Row>
|
</Row>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -1482,7 +1342,7 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Typography.Title level={4} style={{ margin: 0 }}>
|
<Typography.Title level={4} style={{ margin: 0 }}>
|
||||||
{modalContent === 'user' && 'History User Notification'}
|
{modalContent === 'user' && 'User History Notification'}
|
||||||
{modalContent === 'log' && 'Log History Notification'}
|
{modalContent === 'log' && 'Log History Notification'}
|
||||||
</Typography.Title>
|
</Typography.Title>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal, Typography, Card, Row, Col, Avatar, Tag, Button, Space } from 'antd';
|
import { Modal, Typography, Card, Row, Col, Avatar, Tag, Button, Space } from 'antd';
|
||||||
import {
|
import { UserOutlined, PhoneOutlined, CheckCircleOutlined, SyncOutlined, SendOutlined } from '@ant-design/icons';
|
||||||
UserOutlined,
|
|
||||||
PhoneOutlined,
|
|
||||||
CheckCircleOutlined,
|
|
||||||
SyncOutlined,
|
|
||||||
SendOutlined,
|
|
||||||
} from '@ant-design/icons';
|
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
@@ -47,17 +41,9 @@ const UserHistoryModal = ({ visible, onCancel, notificationData }) => {
|
|||||||
const getStatusTag = (status) => {
|
const getStatusTag = (status) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'delivered':
|
case 'delivered':
|
||||||
return (
|
return <Tag icon={<CheckCircleOutlined />} color="success">Delivered</Tag>;
|
||||||
<Tag icon={<CheckCircleOutlined />} color="success">
|
|
||||||
Delivered
|
|
||||||
</Tag>
|
|
||||||
);
|
|
||||||
case 'sent':
|
case 'sent':
|
||||||
return (
|
return <Tag icon={<SyncOutlined spin />} color="processing">Sent</Tag>;
|
||||||
<Tag icon={<SyncOutlined spin />} color="processing">
|
|
||||||
Sent
|
|
||||||
</Tag>
|
|
||||||
);
|
|
||||||
case 'failed':
|
case 'failed':
|
||||||
return <Tag color="error">Failed</Tag>;
|
return <Tag color="error">Failed</Tag>;
|
||||||
default:
|
default:
|
||||||
@@ -69,7 +55,7 @@ const UserHistoryModal = ({ visible, onCancel, notificationData }) => {
|
|||||||
<Modal
|
<Modal
|
||||||
title={
|
title={
|
||||||
<Text strong style={{ fontSize: '18px' }}>
|
<Text strong style={{ fontSize: '18px' }}>
|
||||||
History User Notification
|
User History Notification
|
||||||
</Text>
|
</Text>
|
||||||
}
|
}
|
||||||
open={visible}
|
open={visible}
|
||||||
@@ -92,13 +78,7 @@ const UserHistoryModal = ({ visible, onCancel, notificationData }) => {
|
|||||||
<Avatar size="large" icon={<UserOutlined />} />
|
<Avatar size="large" icon={<UserOutlined />} />
|
||||||
<div>
|
<div>
|
||||||
<Text strong>{user.name}</Text>
|
<Text strong>{user.name}</Text>
|
||||||
<div
|
<div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '4px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<PhoneOutlined style={{ color: '#8c8c8c' }} />
|
<PhoneOutlined style={{ color: '#8c8c8c' }} />
|
||||||
<Text type="secondary">{user.phone}</Text>
|
<Text type="secondary">{user.phone}</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,37 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button, Row, Col, Card, Badge, Typography, Space, Divider } from 'antd';
|
import { Button, Row, Col, Card, Badge, Typography, Space, Divider } from 'antd';
|
||||||
import {
|
import { SendOutlined, MobileOutlined, CheckCircleFilled, ArrowLeftOutlined } from '@ant-design/icons';
|
||||||
SendOutlined,
|
|
||||||
MobileOutlined,
|
|
||||||
CheckCircleFilled,
|
|
||||||
ArrowLeftOutlined,
|
|
||||||
} from '@ant-design/icons';
|
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
// Dummy data for user history
|
// Dummy data for user history
|
||||||
const userHistoryData = [
|
const userHistoryData = [
|
||||||
{
|
{ id: 1, name: 'John Doe', phone: '081234567890', status: 'Delivered', timestamp: '04-11-2025 11:40 WIB' },
|
||||||
id: 1,
|
{ id: 2, name: 'Jane Smith', phone: '087654321098', status: 'Delivered', timestamp: '04-11-2025 11:41 WIB' },
|
||||||
name: 'John Doe',
|
{ id: 3, name: 'Peter Jones', phone: '082345678901', status: 'Delivered', timestamp: '04-11-2025 11:42 WIB' },
|
||||||
phone: '081234567890',
|
|
||||||
status: 'Delivered',
|
|
||||||
timestamp: '04-11-2025 11:40 WIB',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: 'Jane Smith',
|
|
||||||
phone: '087654321098',
|
|
||||||
status: 'Delivered',
|
|
||||||
timestamp: '04-11-2025 11:41 WIB',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: 'Peter Jones',
|
|
||||||
phone: '082345678901',
|
|
||||||
status: 'Delivered',
|
|
||||||
timestamp: '04-11-2025 11:42 WIB',
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const UserHistory = ({ notification, onBack }) => {
|
const UserHistory = ({ notification, onBack }) => {
|
||||||
@@ -41,9 +18,7 @@ const UserHistory = ({ notification, onBack }) => {
|
|||||||
<Col>
|
<Col>
|
||||||
<Space align="center">
|
<Space align="center">
|
||||||
<Button type="text" icon={<ArrowLeftOutlined />} onClick={onBack} />
|
<Button type="text" icon={<ArrowLeftOutlined />} onClick={onBack} />
|
||||||
<Typography.Title level={4} style={{ margin: 0 }}>
|
<Typography.Title level={4} style={{ margin: 0 }}>User History Notification</Typography.Title>
|
||||||
History User Notification
|
|
||||||
</Typography.Title>
|
|
||||||
</Space>
|
</Space>
|
||||||
<Text type="secondary" style={{ marginLeft: '40px' }}>
|
<Text type="secondary" style={{ marginLeft: '40px' }}>
|
||||||
{notification.title} - {notification.issue}
|
{notification.title} - {notification.issue}
|
||||||
@@ -52,34 +27,25 @@ const UserHistory = ({ notification, onBack }) => {
|
|||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
||||||
{userHistoryData.map((user) => (
|
{userHistoryData.map(user => (
|
||||||
<Card
|
<Card key={user.id} style={{ backgroundColor: '#e6f7ff', borderColor: '#91d5ff' }}>
|
||||||
key={user.id}
|
|
||||||
style={{ backgroundColor: '#e6f7ff', borderColor: '#91d5ff' }}
|
|
||||||
>
|
|
||||||
<Row align="middle" justify="space-between">
|
<Row align="middle" justify="space-between">
|
||||||
<Col>
|
<Col>
|
||||||
<Space align="center">
|
<Space align="center">
|
||||||
<Text strong>{user.name}</Text>
|
<Text strong>{user.name}</Text>
|
||||||
<Text>|</Text>
|
<Text>|</Text>
|
||||||
<Text>
|
<Text><MobileOutlined /> {user.phone}</Text>
|
||||||
<MobileOutlined /> {user.phone}
|
|
||||||
</Text>
|
|
||||||
<Text>|</Text>
|
<Text>|</Text>
|
||||||
<Badge status="success" text={user.status} />
|
<Badge status="success" text={user.status} />
|
||||||
</Space>
|
</Space>
|
||||||
<Divider style={{ margin: '8px 0' }} />
|
<Divider style={{ margin: '8px 0' }} />
|
||||||
<Space align="center">
|
<Space align="center">
|
||||||
<CheckCircleFilled style={{ color: '#52c41a' }} />
|
<CheckCircleFilled style={{ color: '#52c41a' }} />
|
||||||
<Text type="secondary">
|
<Text type="secondary">Success Delivered at {user.timestamp}</Text>
|
||||||
Success Delivered at {user.timestamp}
|
|
||||||
</Text>
|
|
||||||
</Space>
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
<Col>
|
<Col>
|
||||||
<Button type="primary" ghost icon={<SendOutlined />}>
|
<Button type="primary" ghost icon={<SendOutlined />}>Resend</Button>
|
||||||
Resend
|
|
||||||
</Button>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import {
|
|||||||
message,
|
message,
|
||||||
Avatar,
|
Avatar,
|
||||||
Tag,
|
Tag,
|
||||||
Badge,
|
|
||||||
Divider,
|
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import {
|
import {
|
||||||
ArrowLeftOutlined,
|
ArrowLeftOutlined,
|
||||||
@@ -35,16 +33,11 @@ import {
|
|||||||
CheckCircleOutlined,
|
CheckCircleOutlined,
|
||||||
SyncOutlined,
|
SyncOutlined,
|
||||||
SendOutlined,
|
SendOutlined,
|
||||||
MobileOutlined,
|
|
||||||
ClockCircleOutlined,
|
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {
|
import {
|
||||||
getNotificationDetail,
|
getNotificationDetail,
|
||||||
createNotificationLog,
|
createNotificationLog,
|
||||||
getNotificationLogByNotificationId,
|
getNotificationLogByNotificationId,
|
||||||
updateIsRead,
|
|
||||||
resendNotificationToUser,
|
|
||||||
resendChatByUser,
|
|
||||||
} from '../../api/notification';
|
} from '../../api/notification';
|
||||||
|
|
||||||
const { Content } = Layout;
|
const { Content } = Layout;
|
||||||
@@ -101,32 +94,38 @@ const transformNotificationData = (apiData) => {
|
|||||||
device_location: apiData.device_location,
|
device_location: apiData.device_location,
|
||||||
brand_name: apiData.brand_name,
|
brand_name: apiData.brand_name,
|
||||||
},
|
},
|
||||||
users: apiData.users || [],
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to get actual users from notification data
|
// Dummy data baru untuk user history
|
||||||
const getUsersFromNotification = (notification) => {
|
const getDummyUsers = (notification) => {
|
||||||
if (!notification || !notification.users) return [];
|
if (!notification) return [];
|
||||||
|
return [
|
||||||
return notification.users.map((user) => ({
|
{
|
||||||
id: user.notification_error_user_id.toString(),
|
id: '1',
|
||||||
name: user.contact_name,
|
name: 'John Doe',
|
||||||
phone: user.contact_phone,
|
phone: '081234567890',
|
||||||
status: user.is_send ? 'Delivered' : 'Pending',
|
status: 'delivered',
|
||||||
loading: user.loading || false,
|
},
|
||||||
timestamp: user.updated_at
|
{
|
||||||
? new Date(user.updated_at)
|
id: '2',
|
||||||
.toLocaleString('id-ID', {
|
name: 'Jane Smith',
|
||||||
day: '2-digit',
|
phone: '082345678901',
|
||||||
month: '2-digit',
|
status: 'sent',
|
||||||
year: 'numeric',
|
},
|
||||||
hour: '2-digit',
|
{
|
||||||
minute: '2-digit',
|
id: '3',
|
||||||
})
|
name: 'Bob Johnson',
|
||||||
.replace('.', ':') + ' WIB'
|
phone: '083456789012',
|
||||||
: 'N/A',
|
status: 'failed',
|
||||||
}));
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
name: 'Alice Brown',
|
||||||
|
phone: '084567890123',
|
||||||
|
status: 'delivered',
|
||||||
|
},
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStatusTag = (status) => {
|
const getStatusTag = (status) => {
|
||||||
@@ -258,9 +257,6 @@ const NotificationDetailTab = (props) => {
|
|||||||
|
|
||||||
// Fetch log history
|
// Fetch log history
|
||||||
fetchLogHistory(notificationId);
|
fetchLogHistory(notificationId);
|
||||||
|
|
||||||
// Fetch using the actual API
|
|
||||||
const resUpdate = await updateIsRead(notificationId);
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Notification not found');
|
throw new Error('Notification not found');
|
||||||
}
|
}
|
||||||
@@ -394,7 +390,7 @@ const NotificationDetailTab = (props) => {
|
|||||||
<Text>{notification.title}</Text>
|
<Text>{notification.title}</Text>
|
||||||
<div style={{ marginTop: '2px' }}>
|
<div style={{ marginTop: '2px' }}>
|
||||||
<Text strong style={{ fontSize: '16px' }}>
|
<Text strong style={{ fontSize: '16px' }}>
|
||||||
Error Code {notification.issue}
|
{notification.issue}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -473,7 +469,7 @@ const NotificationDetailTab = (props) => {
|
|||||||
size={2}
|
size={2}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
>
|
>
|
||||||
{getUsersFromNotification(notification).map((user) => (
|
{getDummyUsers(notification).map((user) => (
|
||||||
<Card
|
<Card
|
||||||
key={user.id}
|
key={user.id}
|
||||||
size="small"
|
size="small"
|
||||||
@@ -482,56 +478,48 @@ const NotificationDetailTab = (props) => {
|
|||||||
<Row align="middle" justify="space-between">
|
<Row align="middle" justify="space-between">
|
||||||
<Col>
|
<Col>
|
||||||
<Space align="center">
|
<Space align="center">
|
||||||
|
<Avatar
|
||||||
|
size="large"
|
||||||
|
icon={<UserOutlined />}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
<Text strong>{user.name}</Text>
|
<Text strong>{user.name}</Text>
|
||||||
<Text>|</Text>
|
<div
|
||||||
<Text>
|
style={{
|
||||||
<MobileOutlined /> {user.phone}
|
display: 'flex',
|
||||||
</Text>
|
alignItems: 'center',
|
||||||
<Text>|</Text>
|
gap: '4px',
|
||||||
<Badge
|
}}
|
||||||
status={
|
>
|
||||||
user.status === 'Delivered'
|
<PhoneOutlined
|
||||||
? 'success'
|
style={{
|
||||||
: 'default'
|
color: '#8c8c8c',
|
||||||
}
|
}}
|
||||||
text={user.status}
|
|
||||||
/>
|
/>
|
||||||
</Space>
|
|
||||||
<Divider style={{ margin: '8px 0' }} />
|
|
||||||
<Space align="center">
|
|
||||||
{user.status === 'Delivered' ? (
|
|
||||||
<CheckCircleFilled
|
|
||||||
style={{ color: '#52c41a' }}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<ClockCircleOutlined
|
|
||||||
style={{ color: '#faad14' }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Text type="secondary">
|
<Text type="secondary">
|
||||||
{user.status === 'Delivered'
|
{user.phone}
|
||||||
? 'Success Delivered at'
|
|
||||||
: 'Status '}{' '}
|
|
||||||
{user.timestamp}
|
|
||||||
</Text>
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Space>
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
<Col>
|
<Col>
|
||||||
<Col>
|
<Space align="center" size="large">
|
||||||
|
{getStatusTag(user.status)}
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
ghost
|
|
||||||
icon={<SendOutlined />}
|
icon={<SendOutlined />}
|
||||||
onClick={async () => {
|
size="small"
|
||||||
await resendChatByUser(
|
onClick={(e) => {
|
||||||
user.id,
|
e.stopPropagation();
|
||||||
user.phone
|
console.log(
|
||||||
|
`Resend to ${user.name}`
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Resend
|
Resend
|
||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -542,25 +530,58 @@ const NotificationDetailTab = (props) => {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row gutter={[8, 8]}>
|
<Row gutter={[8, 8]} style={{ marginBottom: 'px' }}>
|
||||||
<Col xs={24} md={8}>
|
<Col xs={24} md={8}>
|
||||||
<div>
|
|
||||||
<Card
|
<Card
|
||||||
hoverable
|
hoverable
|
||||||
bodyStyle={{ padding: '12px'}}
|
bodyStyle={{ padding: '12px', textAlign: 'center' }}
|
||||||
>
|
>
|
||||||
<Space>
|
<Space>
|
||||||
<BookOutlined
|
<BookOutlined
|
||||||
style={{ fontSize: '16px', color: '#1890ff' }}
|
style={{ fontSize: '16px', color: '#1890ff' }}
|
||||||
/>
|
/>
|
||||||
<Text
|
<Text strong style={{ fontSize: '16px', color: '#262626' }}>
|
||||||
strong
|
|
||||||
style={{ fontSize: '16px', color: '#262626' }}
|
|
||||||
>
|
|
||||||
Handling Guideline
|
Handling Guideline
|
||||||
</Text>
|
</Text>
|
||||||
</Space>
|
</Space>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} md={8}>
|
||||||
|
<Card
|
||||||
|
hoverable
|
||||||
|
bodyStyle={{ padding: '12px', textAlign: 'center' }}
|
||||||
|
>
|
||||||
|
<Space>
|
||||||
|
<ToolOutlined
|
||||||
|
style={{ fontSize: '16px', color: '#1890ff' }}
|
||||||
|
/>
|
||||||
|
<Text strong style={{ fontSize: '16px', color: '#262626' }}>
|
||||||
|
Spare Part
|
||||||
|
</Text>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} md={8}>
|
||||||
|
<Card bodyStyle={{ padding: '12px', textAlign: 'center' }}>
|
||||||
|
<Space>
|
||||||
|
<HistoryOutlined
|
||||||
|
style={{ fontSize: '16px', color: '#1890ff' }}
|
||||||
|
/>
|
||||||
|
<Text strong style={{ fontSize: '16px', color: '#262626' }}>
|
||||||
|
Log Activity
|
||||||
|
</Text>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
<Row gutter={[8, 8]} style={{ marginTop: '-12px' }}>
|
||||||
|
<Col xs={24} md={8}>
|
||||||
|
<Card
|
||||||
|
size="small"
|
||||||
|
title="Guideline Documents"
|
||||||
|
style={{ height: '100%' }}
|
||||||
|
>
|
||||||
<Space
|
<Space
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -574,8 +595,7 @@ const NotificationDetailTab = (props) => {
|
|||||||
.map((sol, index) => (
|
.map((sol, index) => (
|
||||||
<div
|
<div
|
||||||
key={
|
key={
|
||||||
sol.brand_code_solution_id ||
|
sol.brand_code_solution_id || index
|
||||||
index
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{sol.path_document ? (
|
{sol.path_document ? (
|
||||||
@@ -590,8 +610,7 @@ const NotificationDetailTab = (props) => {
|
|||||||
<Text
|
<Text
|
||||||
type="secondary"
|
type="secondary"
|
||||||
style={{
|
style={{
|
||||||
fontSize:
|
fontSize: '10px',
|
||||||
'10px',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
PDF
|
PDF
|
||||||
@@ -603,8 +622,7 @@ const NotificationDetailTab = (props) => {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent:
|
justifyContent:
|
||||||
'space-between',
|
'space-between',
|
||||||
alignItems:
|
alignItems: 'center',
|
||||||
'center',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
@@ -647,11 +665,6 @@ const NotificationDetailTab = (props) => {
|
|||||||
sol.text_solution ? (
|
sol.text_solution ? (
|
||||||
<Card
|
<Card
|
||||||
size="small"
|
size="small"
|
||||||
title={
|
|
||||||
<Text strong>
|
|
||||||
{sol.solution_name}:
|
|
||||||
</Text>
|
|
||||||
}
|
|
||||||
bodyStyle={{
|
bodyStyle={{
|
||||||
padding: '8px 12px',
|
padding: '8px 12px',
|
||||||
marginBottom: '4px',
|
marginBottom: '4px',
|
||||||
@@ -660,8 +673,7 @@ const NotificationDetailTab = (props) => {
|
|||||||
<Text
|
<Text
|
||||||
type="secondary"
|
type="secondary"
|
||||||
style={{
|
style={{
|
||||||
fontSize:
|
fontSize: '10px',
|
||||||
'10px',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{sol.type_solution.toUpperCase()}
|
{sol.type_solution.toUpperCase()}
|
||||||
@@ -669,10 +681,12 @@ const NotificationDetailTab = (props) => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
|
<Text strong>
|
||||||
|
{sol.solution_name}:
|
||||||
|
</Text>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
marginTop:
|
marginTop: '4px',
|
||||||
'4px',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{sol.text_solution}
|
{sol.text_solution}
|
||||||
@@ -696,26 +710,13 @@ const NotificationDetailTab = (props) => {
|
|||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} md={8}>
|
<Col xs={24} md={8}>
|
||||||
<div>
|
|
||||||
<Card
|
<Card
|
||||||
hoverable
|
size="small"
|
||||||
bodyStyle={{ padding: '12px'}}
|
title="Required Spare Parts"
|
||||||
|
style={{ height: '100%' }}
|
||||||
>
|
>
|
||||||
<Space>
|
|
||||||
<ToolOutlined
|
|
||||||
style={{ fontSize: '16px', color: '#1890ff' }}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
strong
|
|
||||||
style={{ fontSize: '16px', color: '#262626' }}
|
|
||||||
>
|
|
||||||
Spare Part
|
|
||||||
</Text>
|
|
||||||
</Space>
|
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -799,11 +800,9 @@ const NotificationDetailTab = (props) => {
|
|||||||
marginTop: '8px',
|
marginTop: '8px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Kode:{' '}
|
Kode: {sparepart.sparepart_code}{' '}
|
||||||
{sparepart.sparepart_code} |
|
| Qty: {sparepart.sparepart_qty}{' '}
|
||||||
Qty:{' '}
|
| Unit:{' '}
|
||||||
{sparepart.sparepart_qty} |
|
|
||||||
Unit:{' '}
|
|
||||||
{sparepart.sparepart_unit}
|
{sparepart.sparepart_unit}
|
||||||
</div>
|
</div>
|
||||||
</Space>
|
</Space>
|
||||||
@@ -824,23 +823,9 @@ const NotificationDetailTab = (props) => {
|
|||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} md={8}>
|
<Col span={8}>
|
||||||
<div>
|
<Card size="small" style={{ height: '100%' }}>
|
||||||
<Card bodyStyle={{ padding: '12px'}}>
|
|
||||||
<Space>
|
|
||||||
<HistoryOutlined
|
|
||||||
style={{ fontSize: '16px', color: '#1890ff' }}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
strong
|
|
||||||
style={{ fontSize: '16px', color: '#262626' }}
|
|
||||||
>
|
|
||||||
Log Activity
|
|
||||||
</Text>
|
|
||||||
</Space>
|
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -850,9 +835,7 @@ const NotificationDetailTab = (props) => {
|
|||||||
size="small"
|
size="small"
|
||||||
bodyStyle={{
|
bodyStyle={{
|
||||||
padding: '8px 12px',
|
padding: '8px 12px',
|
||||||
backgroundColor: isAddingLog
|
backgroundColor: isAddingLog ? '#fafafa' : '#fff',
|
||||||
? '#fafafa'
|
|
||||||
: '#fff',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Space
|
<Space
|
||||||
@@ -862,10 +845,7 @@ const NotificationDetailTab = (props) => {
|
|||||||
>
|
>
|
||||||
{isAddingLog && (
|
{isAddingLog && (
|
||||||
<>
|
<>
|
||||||
<Text
|
<Text strong style={{ fontSize: '12px' }}>
|
||||||
strong
|
|
||||||
style={{ fontSize: '12px' }}
|
|
||||||
>
|
|
||||||
Add New Log / Update Progress
|
Add New Log / Update Progress
|
||||||
</Text>
|
</Text>
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
@@ -873,9 +853,7 @@ const NotificationDetailTab = (props) => {
|
|||||||
placeholder="Tuliskan update penanganan di sini..."
|
placeholder="Tuliskan update penanganan di sini..."
|
||||||
value={newLogDescription}
|
value={newLogDescription}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setNewLogDescription(
|
setNewLogDescription(e.target.value)
|
||||||
e.target.value
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
disabled={submitLoading}
|
disabled={submitLoading}
|
||||||
/>
|
/>
|
||||||
@@ -927,22 +905,18 @@ const NotificationDetailTab = (props) => {
|
|||||||
>
|
>
|
||||||
<Paragraph
|
<Paragraph
|
||||||
style={{ fontSize: '12px', margin: 0 }}
|
style={{ fontSize: '12px', margin: 0 }}
|
||||||
// ellipsis={{ rows: 2 }}
|
ellipsis={{ rows: 2 }}
|
||||||
>
|
>
|
||||||
<Text strong>{log.addedBy.name}:</Text>{' '}
|
<Text strong>{log.addedBy.name}:</Text>{' '}
|
||||||
{log.description}
|
{log.description}
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
<Text
|
<Text type="secondary" style={{ fontSize: '11px' }}>
|
||||||
type="secondary"
|
|
||||||
style={{ fontSize: '11px' }}
|
|
||||||
>
|
|
||||||
{log.timestamp}
|
{log.timestamp}
|
||||||
</Text>
|
</Text>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Space>
|
</Space>
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ const ChangePasswordModal = (props) => {
|
|||||||
try {
|
try {
|
||||||
const response = await changePassword(props.selectedUser.user_id, formData.newPassword);
|
const response = await changePassword(props.selectedUser.user_id, formData.newPassword);
|
||||||
|
|
||||||
// console.log('Change Password Response:', response);
|
console.log('Change Password Response:', response);
|
||||||
|
|
||||||
if (response && response.statusCode === 200) {
|
if (response && response.statusCode === 200) {
|
||||||
NotifOk({
|
NotifOk({
|
||||||
|
|||||||
@@ -220,27 +220,35 @@ const DetailUser = (props) => {
|
|||||||
|
|
||||||
// For update mode: only send email if it has changed
|
// For update mode: only send email if it has changed
|
||||||
if (FormData.user_id) {
|
if (FormData.user_id) {
|
||||||
|
// Only include email if it has changed from original
|
||||||
if (FormData.user_email !== originalEmail) {
|
if (FormData.user_email !== originalEmail) {
|
||||||
payload.user_email = FormData.user_email;
|
payload.user_email = FormData.user_email;
|
||||||
}
|
}
|
||||||
|
// Add is_active for update mode
|
||||||
payload.is_active = FormData.is_active;
|
payload.is_active = FormData.is_active;
|
||||||
} else {
|
} else {
|
||||||
|
// For create mode: always send email
|
||||||
payload.user_email = FormData.user_email;
|
payload.user_email = FormData.user_email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only add role_id if it exists (backend requires number >= 1, no null)
|
||||||
if (FormData.role_id) {
|
if (FormData.role_id) {
|
||||||
payload.role_id = FormData.role_id;
|
payload.role_id = FormData.role_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add password and name for new user (create mode)
|
// Add password and name for new user (create mode)
|
||||||
if (!FormData.user_id) {
|
if (!FormData.user_id) {
|
||||||
payload.user_name = FormData.user_name;
|
payload.user_name = FormData.user_name; // Username only for create
|
||||||
payload.user_password = FormData.password;
|
payload.user_password = FormData.password; // Backend expects 'user_password'
|
||||||
|
// Don't send confirmPassword, is_sa for create
|
||||||
}
|
}
|
||||||
|
// For update mode:
|
||||||
|
// - Don't send 'user_name' (username is immutable)
|
||||||
|
// - is_active is now sent for update mode
|
||||||
|
// - Only send email if it has changed
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// console.log('Payload being sent:', payload);
|
console.log('Payload being sent:', payload);
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
if (!FormData.user_id) {
|
if (!FormData.user_id) {
|
||||||
@@ -249,10 +257,11 @@ const DetailUser = (props) => {
|
|||||||
response = await updateUser(FormData.user_id, payload);
|
response = await updateUser(FormData.user_id, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('Save User Response:', response);
|
console.log('Save User Response:', response);
|
||||||
|
|
||||||
// Check if response is successful
|
// Check if response is successful
|
||||||
if (response && (response.statusCode === 200 || response.statusCode === 201)) {
|
if (response && (response.statusCode === 200 || response.statusCode === 201)) {
|
||||||
|
// If in edit mode and newPassword is provided, change password
|
||||||
if (FormData.user_id && FormData.newPassword) {
|
if (FormData.user_id && FormData.newPassword) {
|
||||||
try {
|
try {
|
||||||
const passwordResponse = await changePassword(
|
const passwordResponse = await changePassword(
|
||||||
@@ -376,9 +385,9 @@ const DetailUser = (props) => {
|
|||||||
search: '',
|
search: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
// console.log('Fetching roles with params:', queryParams.toString());
|
console.log('Fetching roles with params:', queryParams.toString());
|
||||||
const response = await getAllRole(queryParams);
|
const response = await getAllRole(queryParams);
|
||||||
// console.log('Fetched roles response:', response);
|
console.log('Fetched roles response:', response);
|
||||||
|
|
||||||
// Handle different response structures
|
// Handle different response structures
|
||||||
if (response && response.data) {
|
if (response && response.data) {
|
||||||
@@ -399,7 +408,7 @@ const DetailUser = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setRoleList(roles);
|
setRoleList(roles);
|
||||||
// console.log('Setting role list:', roles);
|
console.log('Setting role list:', roles);
|
||||||
} else {
|
} else {
|
||||||
// Add mock data as fallback
|
// Add mock data as fallback
|
||||||
console.warn('No response data, using mock data');
|
console.warn('No response data, using mock data');
|
||||||
@@ -409,7 +418,7 @@ const DetailUser = (props) => {
|
|||||||
{ role_id: 3, role_name: 'User', role_level: 3 },
|
{ role_id: 3, role_name: 'User', role_level: 3 },
|
||||||
];
|
];
|
||||||
setRoleList(mockRoles);
|
setRoleList(mockRoles);
|
||||||
// console.log('Setting mock role list:', mockRoles);
|
console.log('Setting mock role list:', mockRoles);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching roles:', error);
|
console.error('Error fetching roles:', error);
|
||||||
@@ -420,7 +429,7 @@ const DetailUser = (props) => {
|
|||||||
{ role_id: 3, role_name: 'User', role_level: 3 },
|
{ role_id: 3, role_name: 'User', role_level: 3 },
|
||||||
];
|
];
|
||||||
setRoleList(mockRoles);
|
setRoleList(mockRoles);
|
||||||
// console.log('Setting mock role list due to error:', mockRoles);
|
console.log('Setting mock role list due to error:', mockRoles);
|
||||||
|
|
||||||
// Only show error notification if we don't have fallback data
|
// Only show error notification if we don't have fallback data
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
@@ -1137,7 +1146,9 @@ const DetailUser = (props) => {
|
|||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
{errors.role_id && (
|
{errors.role_id && (
|
||||||
<Text style={{ color: 'red', fontSize: '12px' }}>{errors.role_id}</Text>
|
<Text style={{ color: 'red', fontSize: '12px' }}>
|
||||||
|
{errors.role_id}
|
||||||
|
</Text>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
import React, { useState, useEffect, memo } from 'react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { Button, Typography } from 'antd';
|
|
||||||
import { resetWA } from '../../api/whatsapp-control';
|
|
||||||
import { useBreadcrumb } from '../../layout/LayoutBreadcrumb';
|
|
||||||
import { ReloadOutlined } from '@ant-design/icons';
|
|
||||||
|
|
||||||
const { Text } = Typography;
|
|
||||||
|
|
||||||
const IndexWhatsAppControl = memo(function IndexWhatsAppControl() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const { setBreadcrumbItems } = useBreadcrumb();
|
|
||||||
|
|
||||||
const [isPlaying, setIsPlaying] = useState(true);
|
|
||||||
|
|
||||||
const url = import.meta.env.VITE_WHATSAPP_URL;
|
|
||||||
|
|
||||||
const handleReset = async () => {
|
|
||||||
setIsPlaying(false);
|
|
||||||
await resetWA();
|
|
||||||
setIsPlaying(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const token = localStorage.getItem('token');
|
|
||||||
|
|
||||||
if (token) {
|
|
||||||
setBreadcrumbItems([
|
|
||||||
{
|
|
||||||
title: (
|
|
||||||
<Text strong style={{ fontSize: '14px' }}>
|
|
||||||
• WhatsApp Control Panel
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
navigate('/signin');
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ padding: '20px' }}>
|
|
||||||
<div style={{ marginBottom: 20 }}>
|
|
||||||
<Button type="primary" onClick={handleReset} style={{ marginRight: 10 }}>
|
|
||||||
<ReloadOutlined /> Restart WhatsApp
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border: '1px solid #ddd',
|
|
||||||
height: '700px',
|
|
||||||
background: '#fafafa',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isPlaying ? (
|
|
||||||
<iframe
|
|
||||||
src={url}
|
|
||||||
title="WhatsApp Preview"
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
border: 'none',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
height: '100%',
|
|
||||||
color: '#888',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Memuat Halaman WhatsApp QR Code
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default IndexWhatsAppControl;
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
import React, { useState, useEffect, useRef, memo } from 'react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { Button, Typography, message } from 'antd';
|
|
||||||
import { resetWA } from '../../api/web-control';
|
|
||||||
import { useBreadcrumb } from '../../layout/LayoutBreadcrumb';
|
|
||||||
import { ReloadOutlined } from '@ant-design/icons';
|
|
||||||
|
|
||||||
const { Text } = Typography;
|
|
||||||
|
|
||||||
const IndexWebControl = memo(function IndexWebControl() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const { setBreadcrumbItems } = useBreadcrumb();
|
|
||||||
|
|
||||||
const [isPlaying, setIsPlaying] = useState(true);
|
|
||||||
const [currentUrl, setCurrentUrl] = useState('http://localhost:9531');
|
|
||||||
const iframeRef = useRef(null);
|
|
||||||
|
|
||||||
const handleReset = async () => {
|
|
||||||
setIsPlaying(false);
|
|
||||||
await resetWA();
|
|
||||||
setIsPlaying(true);
|
|
||||||
// Kembali ke halaman login setelah reset
|
|
||||||
setCurrentUrl('https://localhost:9531');
|
|
||||||
message.success('WhatsApp berhasil di-restart');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fungsi untuk redirect ke QR View
|
|
||||||
const redirectToQRView = () => {
|
|
||||||
setCurrentUrl('https://localhost:9531/qrview');
|
|
||||||
message.info('Redirecting to QR View...');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fungsi untuk kembali ke login
|
|
||||||
const backToLogin = () => {
|
|
||||||
setCurrentUrl('https://localhost:9531');
|
|
||||||
message.info('Back to login page');
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const token = localStorage.getItem('token');
|
|
||||||
if (token) {
|
|
||||||
setBreadcrumbItems([
|
|
||||||
{
|
|
||||||
title: (
|
|
||||||
<Text strong style={{ fontSize: '14px' }}>
|
|
||||||
• Web Control Panel
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
navigate('/signin');
|
|
||||||
}
|
|
||||||
}, [navigate, setBreadcrumbItems]);
|
|
||||||
|
|
||||||
// Mendengarkan pesan dari iframe
|
|
||||||
useEffect(() => {
|
|
||||||
const handleMessage = (event) => {
|
|
||||||
// Terima pesan dari domain manapun untuk testing
|
|
||||||
console.log('Message received from:', event.origin);
|
|
||||||
console.log('Message data:', event.data);
|
|
||||||
|
|
||||||
// Cek apakah ini pesan login success
|
|
||||||
if (event.data) {
|
|
||||||
// Jika pesan adalah string
|
|
||||||
if (typeof event.data === 'string') {
|
|
||||||
const lowerData = event.data.toLowerCase();
|
|
||||||
if (
|
|
||||||
lowerData.includes('login') ||
|
|
||||||
lowerData.includes('success') ||
|
|
||||||
lowerData.includes('authenticated') ||
|
|
||||||
lowerData.includes('qrview')
|
|
||||||
) {
|
|
||||||
console.log('Login detected via string message');
|
|
||||||
redirectToQRView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jika pesan adalah object
|
|
||||||
if (typeof event.data === 'object') {
|
|
||||||
if (
|
|
||||||
event.data.type === 'LOGIN_SUCCESS' ||
|
|
||||||
event.data.status === 'success' ||
|
|
||||||
event.data.logged_in === true ||
|
|
||||||
event.data.redirect === true
|
|
||||||
) {
|
|
||||||
console.log('Login detected via object message');
|
|
||||||
redirectToQRView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('message', handleMessage);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('message', handleMessage);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Alternative: Coba dengan timer (jika postMessage tidak berfungsi)
|
|
||||||
useEffect(() => {
|
|
||||||
// Jika tidak ada pesan dari iframe, coba redirect otomatis setelah 10 detik
|
|
||||||
// Asumsi: login biasanya selesai dalam 10 detik
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
if (currentUrl === 'https://localhost:9531') {
|
|
||||||
console.log('Auto redirect after 10 seconds (fallback)');
|
|
||||||
redirectToQRView();
|
|
||||||
}
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, [currentUrl]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ padding: '20px' }}>
|
|
||||||
<div style={{ marginBottom: 20, display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
|
|
||||||
<Button type="primary" onClick={handleReset}>
|
|
||||||
<ReloadOutlined /> Restart WhatsApp
|
|
||||||
</Button>
|
|
||||||
{/* <Button onClick={redirectToQRView} type="default">
|
|
||||||
Redirect ke QR View
|
|
||||||
</Button>
|
|
||||||
<Button onClick={backToLogin} type="default">
|
|
||||||
Kembali ke Login
|
|
||||||
</Button> */}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border: '1px solid #ddd',
|
|
||||||
height: '700px',
|
|
||||||
background: '#fafafa',
|
|
||||||
position: 'relative',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isPlaying ? (
|
|
||||||
<iframe
|
|
||||||
key={currentUrl} // Force re-render saat URL berubah
|
|
||||||
ref={iframeRef}
|
|
||||||
src={currentUrl}
|
|
||||||
title="Web Preview"
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
border: 'none',
|
|
||||||
}}
|
|
||||||
onLoad={() => {
|
|
||||||
console.log('Iframe loaded with URL:', currentUrl);
|
|
||||||
// Hanya log, tidak mencoba mengakses URL untuk menghindari error CORS
|
|
||||||
}}
|
|
||||||
onError={(e) => console.error('Iframe error:', e)}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
height: '100%',
|
|
||||||
color: '#888',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Memuat Halaman WhatsApp QR Code
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default IndexWebControl;
|
|
||||||