Compare commits

...

78 Commits

Author SHA1 Message Date
ce55126bf8 Merge pull request 'add space' (#43) from lavoce into main
Reviewed-on: #43
2026-04-14 07:25:48 +00:00
zain94rif
9000d5da71 add space 2026-04-14 14:24:06 +07:00
11ac6ad9ba Merge pull request 'lavoce' (#42) from lavoce into main
Reviewed-on: #42
2026-04-10 05:35:38 +00:00
zain94rif
bd2dade932 fix(svg): change compressor A, B, C image position 2026-04-09 15:25:00 +07:00
zain94rif
da1adce118 fix(svg): change svg compressor B position 2026-04-09 11:02:59 +07:00
zain94rif
b64fa47a38 fix(func): remove unuse function 2026-04-08 14:35:02 +07:00
zain94rif
4cca3fb95a fix(color): color conditiion in air dryer A, B, C & remove H(text) 2026-04-08 14:28:41 +07:00
zain94rif
13fcc126a2 fix(local): hostman access from user 2026-04-06 14:02:02 +07:00
zain94rif
75db6eb209 fix(local): add middleware for local access only 2026-04-06 12:54:16 +07:00
zain94rif
9c664cd9a3 fix(env): change whatsApp Url from env 2026-04-06 10:33:44 +07:00
zain94rif
34beee4975 fix(name): change name from Web Control to WhatsApp Control 2026-04-02 14:03:17 +07:00
8becbc2a6b Repair WhatsApp Control 2026-03-31 10:37:44 +07:00
ea3e748684 fix(api): add asyn await for the effect 2026-03-19 11:03:04 +07:00
517661a237 fix(icon): change the icon, text & only 1 button 2026-03-18 14:58:20 +07:00
9c405fa0de fix(api): change endpoint to qr & resize frame 2026-03-18 12:49:44 +07:00
9e3ad19591 fix(api): add api for reset web and WA update 2026-03-16 14:54:00 +07:00
986026c3af feat(menu): add new menu web control 2026-03-16 11:09:22 +07:00
zain94rif
b1d8d8bc9a fix(color): changer color in compressor ABC - start/stop 2026-03-03 14:34:27 +07:00
zain94rif
df0901a9b3 fix(svg): change the SVG image compressor B 2026-03-03 12:40:51 +07:00
zain94rif
10824d4207 fix: back to old view, no add buttom 2026-03-02 15:52:44 +07:00
zain94rif
a60dcd104b feat: add buttom for Daftar Error Code 2026-02-24 15:41:31 +07:00
d02d7d87da Merge pull request 'Repair image svg' (#41) from lavoce into main
Reviewed-on: #41
2026-02-12 05:32:33 +00:00
66a9a4e57e Repair image svg 2026-02-12 12:31:36 +07:00
255c1e64c7 Merge pull request 'lavoce' (#40) from lavoce into main
Reviewed-on: #40
2026-01-20 04:32:42 +00:00
zain94rif
2b3d8ea3d2 feat(mqtt): update notification use websocket 2026-01-14 11:26:39 +07:00
zain94rif
c0fe3aaca1 fix(icon): change size & color icon svg 2026-01-13 17:04:50 +07:00
zain94rif
e8da716e8f feat(svg): add new icon svg open mail 2026-01-13 16:31:21 +07:00
90b882daf3 Merge pull request 'fix(color): change design & color for icon notification' (#39) from lavoce into main
Reviewed-on: #39
2026-01-13 05:39:38 +00:00
zain94rif
0ffcf4c3c0 fix(color): change design & color for icon notification 2026-01-12 15:35:41 +07:00
cc6a52ccbf Merge pull request 'lavoce' (#38) from lavoce into main
Reviewed-on: #38
2026-01-12 04:29:21 +00:00
zain94rif
c2163cec5e Merge branch 'lavoce' of https://gitea.idetama.id/yogiedigital/cod-fe into lavoce 2026-01-08 17:25:23 +07:00
zain94rif
d5866ceae4 fix(api): search use api 2026-01-08 17:25:17 +07:00
03d5646565 Merge pull request 'lavoce' (#37) from lavoce into main
Reviewed-on: #37
2026-01-08 07:44:22 +00:00
6fdb259246 fixing validate solution optional in brand error code 2026-01-08 14:32:27 +07:00
0aad43c751 add label error code in list notification 2026-01-08 14:24:32 +07:00
d988d47e30 fixing layout mobile detail notification 2026-01-08 14:17:38 +07:00
zain94rif
e08eaaa43e fix(text): add 'error code' & move solution name 2026-01-08 13:55:01 +07:00
4d8af01316 Merge pull request 'fixing typo detail notification user' (#36) from lavoce into main
Reviewed-on: #36
2026-01-08 05:38:53 +00:00
8f32f29c03 Merge pull request 'lavoce' (#35) from lavoce into main
Reviewed-on: #35
2026-01-08 04:52:16 +00:00
5a7d64a05b Merge pull request 'fix: resize add log card' (#34) from lavoce into main
Reviewed-on: #34
2026-01-07 03:33:48 +00:00
e74b802a60 Merge pull request 'lavoce' (#33) from lavoce into main
Reviewed-on: #33
2026-01-06 11:30:27 +00:00
f436865b7f Merge pull request 'lavoce' (#32) from lavoce into main
Reviewed-on: #32
2026-01-05 03:41:39 +00:00
48437c3c50 Merge pull request 'lavoce' (#30) from lavoce into main
Reviewed-on: #30
2025-12-31 03:20:51 +00:00
a33c9b3b92 Merge pull request 'lavoce' (#29) from lavoce into main
Reviewed-on: #29
2025-12-23 05:22:06 +00:00
58d1f5c7ab Merge pull request 'Repair and replace svg' (#28) from lavoce into main
Reviewed-on: #28
2025-12-22 09:38:05 +00:00
c10a5bf62d Merge pull request 'lavoce' (#27) from lavoce into main
Reviewed-on: #27
2025-12-22 09:28:34 +00:00
6cc5042956 Merge pull request 'repair' (#26) from lavoce into main
Reviewed-on: #26
2025-11-28 07:17:06 +00:00
5079f8d316 Merge pull request 'lavoce' (#25) from lavoce into main
Reviewed-on: #25
2025-11-28 07:12:41 +00:00
7073390de7 Merge pull request 'lavoce' (#24) from lavoce into main
Reviewed-on: #24
2025-11-28 05:50:36 +00:00
4226a24e79 Merge pull request 'lavoce' (#23) from lavoce into main
Reviewed-on: #23
2025-11-28 05:10:26 +00:00
038009433f Merge pull request 'lavoce' (#22) from lavoce into main
Reviewed-on: #22
2025-11-25 03:50:54 +00:00
64ba51b17c Merge pull request 'lavoce' (#21) from lavoce into main
Reviewed-on: #21
2025-11-20 03:44:05 +00:00
47d0638a42 Merge pull request 'lavoce' (#20) from lavoce into main
Reviewed-on: #20
2025-11-19 01:05:19 +00:00
d8c5f3ed44 Merge pull request 'lavoce' (#19) from lavoce into main
Reviewed-on: #19
2025-11-18 00:26:36 +00:00
affd9146bb Merge pull request 'lavoce' (#18) from lavoce into main
Reviewed-on: #18
2025-11-17 08:27:39 +00:00
4022b3f8f4 Merge pull request 'lavoce' (#17) from lavoce into main
Reviewed-on: #17
2025-11-10 07:57:17 +00:00
446a4e2b95 Merge pull request 'lavoce' (#16) from lavoce into main
Reviewed-on: #16
2025-11-10 06:33:35 +00:00
83a475c708 Merge pull request 'Repair beautiful apps' (#15) from lavoce into main
Reviewed-on: #15
2025-11-04 10:01:47 +00:00
ab1c510a77 Merge pull request 'Repair bg-signin' (#14) from lavoce into main
Reviewed-on: #14
2025-11-04 08:48:59 +00:00
59859c6d18 Update public/web.config 2025-11-04 07:03:57 +00:00
2bd27937dc Update public/web.config 2025-11-04 07:02:55 +00:00
1058c660d6 Update public/web.config 2025-11-04 07:01:10 +00:00
35b2167791 Update public/web.config 2025-11-04 06:53:05 +00:00
ec676983d0 Update .gitignore 2025-11-04 06:51:39 +00:00
c07c5f8235 Update .gitignore 2025-11-04 06:47:31 +00:00
b32ad97034 Merge pull request 'Add side bar menus mobile mode' (#13) from lavoce into main
Reviewed-on: #13
2025-11-04 06:42:09 +00:00
76244f6f6e Merge pull request 'lavoce' (#12) from lavoce into main
Reviewed-on: #12
2025-11-04 06:23:15 +00:00
0a128cbb3c Merge pull request 'lavoce' (#11) from lavoce into main
Reviewed-on: #11
2025-10-28 09:47:36 +00:00
bd4ab26680 Merge pull request 'lavoce' (#10) from lavoce into main
Reviewed-on: #10
2025-10-28 04:48:54 +00:00
3e728a1ff5 Merge pull request 'lavoce' (#9) from lavoce into main
Reviewed-on: #9
2025-10-27 03:48:58 +00:00
9db143972e Merge pull request 'lavoce' (#8) from lavoce into main
Reviewed-on: #8
2025-10-25 09:19:36 +00:00
029ea269a7 Merge pull request 'lavoce' (#7) from lavoce into main
Reviewed-on: #7
2025-10-24 05:43:32 +00:00
4cdaa042da Merge pull request 'lavoce' (#6) from lavoce into main
Reviewed-on: #6
2025-10-23 07:28:11 +00:00
56af2a16c0 Merge pull request 'update file svg to src assets' (#5) from lavoce into main
Reviewed-on: #5
2025-10-23 04:52:13 +00:00
deadf2ffb4 Merge pull request 'lavoce' (#4) from lavoce into main
Reviewed-on: #4
2025-10-23 04:27:57 +00:00
4da80c7089 Merge pull request 'lavoce' (#3) from lavoce into main
Reviewed-on: #3
2025-10-22 05:59:57 +00:00
56e3ce78a6 Merge pull request 'lavoce' (#2) from lavoce into main
Reviewed-on: #2
2025-10-20 04:06:02 +00:00
7c2a019dd2 Merge pull request 'lavoce' (#1) from lavoce into main
Reviewed-on: #1
2025-09-17 08:39:35 +00:00
21 changed files with 2043 additions and 1599 deletions

View File

@@ -3,4 +3,8 @@ VITE_API_SERVER=http://localhost:9530/api
VITE_MQTT_SERVER=ws://localhost:1884
VITE_MQTT_USERNAME=
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
View File

@@ -6,6 +6,7 @@ yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
*.config
node_modules
dist

View File

@@ -1,48 +1,48 @@
{
"name": "antd-vite-react-sypiu",
"homepage": "/dashboard/home",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@ant-design/icons": "^6.0.0",
"@nivo/line": "^0.88.0",
"@nivo/pie": "^0.88.0",
"antd": "^5.15.2",
"axios": "^1.8.4",
"browser-image-compression": "^2.0.2",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.13",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
"html2canvas": "^1.4.1",
"jspdf": "^3.0.4",
"jspdf-autotable": "^5.0.2",
"mqtt": "^5.14.0",
"qrcode": "^1.5.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.11.0",
"react-router-dom": "^6.22.3",
"react-svg": "^16.3.0",
"recharts": "^3.6.0",
"sweetalert2": "^11.17.2"
},
"devDependencies": {
"@types/react": "^18.2.64",
"@types/react-dom": "^18.2.21",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"vite": "^5.1.6"
},
"packageManager": "pnpm@10.2.1+sha512.398035c7bd696d0ba0b10a688ed558285329d27ea994804a52bad9167d8e3a72bcb993f9699585d3ca25779ac64949ef422757a6c31102c12ab932e5cbe5cc92"
"name": "antd-vite-react-call-of-duty",
"homepage": "/dashboard/home",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite --host 0.0.0.0 --port 8592",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@ant-design/icons": "^6.0.0",
"@nivo/line": "^0.88.0",
"@nivo/pie": "^0.88.0",
"antd": "^5.15.2",
"axios": "^1.8.4",
"browser-image-compression": "^2.0.2",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.13",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
"html2canvas": "^1.4.1",
"jspdf": "^3.0.4",
"jspdf-autotable": "^5.0.2",
"mqtt": "^5.14.0",
"qrcode": "^1.5.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.11.0",
"react-router-dom": "^6.22.3",
"react-svg": "^16.3.0",
"recharts": "^3.6.0",
"sweetalert2": "^11.17.2"
},
"devDependencies": {
"@types/react": "^18.2.64",
"@types/react-dom": "^18.2.21",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"vite": "^5.1.6"
},
"packageManager": "pnpm@10.2.1+sha512.398035c7bd696d0ba0b10a688ed558285329d27ea994804a52bad9167d8e3a72bcb993f9699585d3ca25779ac64949ef422757a6c31102c12ab932e5cbe5cc92"
}

View File

@@ -3,7 +3,7 @@
<system.webServer>
<rewrite>
<rules>
<rule name="reactViteSypiu">
<rule name="CallOfDuty">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />

View File

@@ -36,6 +36,7 @@ import IndexNotification from './pages/notification/IndexNotification';
import IndexRole from './pages/role/IndexRole';
import IndexUser from './pages/user/IndexUser';
import IndexContact from './pages/contact/IndexContact';
import IndexWhatsAppControl from './pages/whatsAppControl/IndexWhatsAppControl';
import DetailNotificationTab from './pages/notificationDetail/IndexNotificationDetail';
import IndexVerificationSparepart from './pages/verificationSparepart/IndexVerificationSparepart';
@@ -144,6 +145,10 @@ const App = () => {
<Route index element={<IndexUser />} />
</Route>
<Route path="/whatsapp-control" element={<ProtectedRoute />}>
<Route index element={<IndexWhatsAppControl />} />
</Route>
<Route path="/contact" element={<ProtectedRoute />}>
<Route index element={<IndexContact />} />
</Route>

View File

@@ -82,6 +82,15 @@ const resendChatAllUser = async (notificationId) => {
return response.data;
};
// Searching
const searchData = async (queryParams) => {
const response = await SendRequest({
method: 'get',
prefix: `notification?criteria=${queryParams}`,
});
return response.data;
};
export {
getAllNotification,
getNotificationById,
@@ -92,4 +101,5 @@ export {
resendNotificationToUser,
resendChatByUser,
resendChatAllUser,
searchData,
};

View File

@@ -0,0 +1,12 @@
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 };

View File

@@ -37,17 +37,14 @@
<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>
<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>
<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>
<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>
<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>
<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; 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)"/>
@@ -110,12 +107,10 @@
<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>
<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>
<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>
<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: 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;">
@@ -179,43 +174,36 @@
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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)">####.##</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)" 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="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;"/>
<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);"/>
<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>
<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>
<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>
<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, 2.097643, 3.138935)">HTD</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, -0.902357, 3.138935)" id="c_4015">#####</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);"/>
<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>
<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>
<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="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;"/>
<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);"/>
@@ -229,17 +217,10 @@
<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"/>
<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>
<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>
<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>
<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: 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.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>
@@ -251,11 +232,16 @@
<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="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="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, 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, 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.031" cy="234.094" rx="13.582" ry="12.517" id="c_4021"/>
<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(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(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>

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -186,17 +186,16 @@
<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>
<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)">####.##</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)" 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="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;"/>
<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);"/>
<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>
<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>
<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>
<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, 2.097643, 3.138935)">HTD</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, 0.097643, 3.138935)" id="c_5015">#####</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);"/>
<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>
@@ -218,16 +217,10 @@
<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"/>
<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>
<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>
<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>
<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: 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.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>
@@ -239,12 +232,16 @@
<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="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.483" 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="336.418" cy="237.517" rx="13.582" ry="12.517" id=""/>
<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(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(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(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(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(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="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="335.418" cy="321.016" 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>

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -186,17 +186,16 @@
<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>
<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)">####.##</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)" 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="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;"/>
<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);"/>
<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>
<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>
<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>
<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, 2.097643, 3.138935)">HTD</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.902357, 3.138935)" id="c_6015">#####</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);"/>
<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>
@@ -218,17 +217,10 @@
<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"/>
<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>
<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>
<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>
<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: 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.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>
@@ -240,12 +232,16 @@
<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="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.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="336.418" cy="237.517" rx="13.582" ry="12.517" id=""/>
<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(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, 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="335.623" cy="320.662" 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(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(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(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(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>

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 177 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 177 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -10,7 +10,8 @@ const topics = [
'PIU_COD/COMPRESSOR/OVERVIEW',
'PIU_COD/COMPRESSOR/COMPRESSOR_A',
'PIU_COD/COMPRESSOR/COMPRESSOR_B',
'PIU_COD/COMPRESSOR/COMPRESSOR_C'
'PIU_COD/COMPRESSOR/COMPRESSOR_C',
'PIU_COD/ERROR_CODE/SIM',
];
const options = {
keepalive: 30,
@@ -73,29 +74,97 @@ 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) => {
client.on('message', (topic, message) => {
// console.log(topic ,' = ', listenTopic);
if (topic === listenTopic) {
const objChanel = JSON.parse(message);
Object.entries(objChanel).forEach(([key, value]) => {
// console.log(key, value);
const el = svg.getElementById(key);
if (el) {
if (value === true) {
el.style.display = ''; // sembunyikan
} else if (value === false) {
el.style.display = 'none';
} else if (!isNaN(value)) {
el.textContent = Number(value ?? 0.0).toFixed(2);
} else {
el.textContent = value;
}
if (!el) return;
// else if (el.id === 'c_2014' || el.id === 'c_2024') {
// el.setAttribute('text-anchor', 'middle');
// el.setAttribute('x', '10%');
// }
if (typeof value === 'boolean') {
handleBoolean(svg, el, value);
} else if (!isNaN(value)) {
handleNumber(el, value);
} else {
handleOther(el, value);
}
});
const target = svg.querySelector('text[x="225.25"][y="537.752"]');
if (target) target.remove();
}
});
};
export { publishMessage, listenMessage, setValSvg };
// === NOTIFICATION LISTENER ===
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 };

View File

@@ -7,6 +7,7 @@ import {
DatabaseOutlined,
SettingOutlined,
UserOutlined,
GlobalOutlined,
AntDesignOutlined,
ShoppingCartOutlined,
ShoppingOutlined,
@@ -36,6 +37,14 @@ import {
} from '@ant-design/icons';
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 = [
{
@@ -225,6 +234,19 @@ const allItems = [
</Link>
),
},
...(isLocal
? [
{
key: 'whatsapp-control',
icon: <GlobalOutlined style={{ fontSize: '19px' }} />,
label: (
<Link to="/whatsapp-control" className="fontMenus">
WhatsApp Control
</Link>
),
},
]
: []),
// {
// key: 'jadwal-shift',
// icon: <CalendarOutlined style={{ fontSize: '19px' }} />,
@@ -250,6 +272,7 @@ const LayoutMenu = () => {
if (pathname === '/dashboard/home') return 'home';
if (pathname === '/user') return 'user';
if (pathname === '/role') return 'role';
if (pathname === '/whatsapp-control') return 'whatsapp-control';
if (pathname === '/notification') return 'notification';
if (pathname === '/jadwal-shift') return 'jadwal-shift';
if (pathname === '/contact') return 'contact';

View File

@@ -479,14 +479,14 @@ const EditBrandDevice = () => {
return;
}
if (!solutionData || solutionData.length === 0) {
NotifAlert({
icon: 'warning',
title: 'Perhatian',
message: 'Setiap error code harus memiliki minimal 1 solution!',
});
return;
}
// if (!solutionData || solutionData.length === 0) {
// NotifAlert({
// icon: 'warning',
// title: 'Perhatian',
// message: 'Setiap error code harus memiliki minimal 1 solution!',
// });
// return;
// }
const formattedSolutions = solutionData.map(solution => {
const solutionType = solution.type || 'text';

View File

@@ -1,6 +1,12 @@
import React, { useState, useEffect, useMemo } from 'react';
import { Card, Input, Button, Row, Col, Empty } from 'antd';
import { PlusOutlined, SearchOutlined, DeleteOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons';
import {
PlusOutlined,
SearchOutlined,
DeleteOutlined,
LeftOutlined,
RightOutlined,
} from '@ant-design/icons';
import { getErrorCodesByBrandId, deleteErrorCode } from '../../../../api/master-brand';
import { NotifAlert, NotifOk, NotifConfirmDialog } from '../../../../components/Global/ToastNotif';
@@ -16,7 +22,7 @@ const ListErrorCode = ({
onSearch,
onSearchClear,
isReadOnly = false,
errorCodes: propErrorCodes = null
errorCodes: propErrorCodes = null,
}) => {
const [errorCodes, setErrorCodes] = useState([]);
const [loading, setLoading] = useState(false);
@@ -52,12 +58,12 @@ const ListErrorCode = ({
if (response && response.statusCode === 200) {
const apiErrorData = response.data || [];
const allErrorCodes = [
...apiErrorData.map(ec => ({
...apiErrorData.map((ec) => ({
...ec,
tempId: `existing_${ec.error_code_id}`,
status: 'existing'
status: 'existing',
})),
...tempErrorCodes.filter(ec => ec.status !== 'deleted')
...tempErrorCodes.filter((ec) => ec.status !== 'deleted'),
];
setErrorCodes(allErrorCodes);
@@ -82,11 +88,9 @@ const ListErrorCode = ({
useEffect(() => {
if (isReadOnly && propErrorCodes) {
setErrorCodes(propErrorCodes);
setLoading(false);
} else {
fetchErrorCodes();
}
}, [brandId, queryParams, tempErrorCodes, trigerFilter, isReadOnly, propErrorCodes]);
@@ -126,20 +130,19 @@ const ListErrorCode = ({
title: 'Hapus Error Code',
message: `Apakah Anda yakin ingin menghapus error code ${item.error_code}?`,
onConfirm: () => performDelete(item),
onCancel: () => { },
confirmButtonText: 'Hapus'
onCancel: () => {},
confirmButtonText: 'Hapus',
});
}
};
const performDelete = async (item) => {
try {
if (!item.error_code_id || item.error_code_id === 'undefined') {
NotifAlert({
icon: 'error',
title: 'Error',
message: 'Error code ID tidak valid'
message: 'Error code ID tidak valid',
});
return;
}
@@ -148,7 +151,7 @@ const ListErrorCode = ({
NotifAlert({
icon: 'error',
title: 'Error',
message: 'Brand ID tidak valid'
message: 'Brand ID tidak valid',
});
return;
}
@@ -159,21 +162,21 @@ const ListErrorCode = ({
NotifOk({
icon: 'success',
title: 'Berhasil',
message: 'Error code berhasil dihapus'
message: 'Error code berhasil dihapus',
});
fetchErrorCodes();
} else {
NotifAlert({
icon: 'error',
title: 'Gagal',
message: 'Gagal menghapus error code'
message: 'Gagal menghapus error code',
});
}
} catch (error) {
NotifAlert({
icon: 'error',
title: 'Error',
message: 'Terjadi kesalahan saat menghapus error code'
message: 'Terjadi kesalahan saat menghapus error code',
});
}
};
@@ -181,8 +184,8 @@ const ListErrorCode = ({
return (
<Card
title="Daftar Error Code"
style={{ width: '100%', minWidth: '472px' }}
styles={{ body: { padding: '12px' } }}
style={{ width: '100%', minWidth: '300px' }}
bodyStyle={{ padding: '12px' }}
>
<Input.Search
placeholder="Cari error code..."
@@ -203,7 +206,7 @@ const ListErrorCode = ({
style={{
backgroundColor: '#23A55A',
borderColor: '#23A55A',
height: '32px'
height: '32px',
}}
>
Search
@@ -217,19 +220,18 @@ const ListErrorCode = ({
}}
/>
<div style={{
height: '90vh',
border: '1px solid #d9d9d9',
borderRadius: '6px',
overflow: 'auto',
marginBottom: 12,
backgroundColor: '#fafafa'
}}>
<div
style={{
height: '90vh',
border: '1px solid #d9d9d9',
borderRadius: '6px',
overflow: 'auto',
marginBottom: 12,
backgroundColor: '#fafafa',
}}
>
{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' }}>
{errorCodes.map((item) => (
@@ -240,13 +242,25 @@ const ListErrorCode = ({
padding: '8px 12px',
borderRadius: '6px',
marginBottom: '4px',
border: selectedErrorCode?.tempId === item.tempId ? '2px solid #23A55A' : '1px solid #d9d9d9',
backgroundColor: selectedErrorCode?.tempId === item.tempId ? '#f6ffed' : '#fff',
transition: 'all 0.2s ease'
border:
selectedErrorCode?.tempId === item.tempId
? '2px solid #23A55A'
: '1px solid #d9d9d9',
backgroundColor:
selectedErrorCode?.tempId === item.tempId
? '#f6ffed'
: '#fff',
transition: 'all 0.2s ease',
}}
onClick={() => onErrorCodeSelect(item)}
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<div style={{ flex: 1 }}>
<div style={{ fontWeight: 'bold', fontSize: '12px' }}>
{item.error_code}
@@ -266,7 +280,7 @@ const ListErrorCode = ({
padding: '2px 6px',
height: '24px',
fontSize: '11px',
border: '1px solid #ff4d4f'
border: '1px solid #ff4d4f',
}}
/>
)}
@@ -292,9 +306,15 @@ const ListErrorCode = ({
onClick={handlePrevious}
disabled={pagination.current_page <= 1}
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}
</span>
<Button
@@ -302,8 +322,7 @@ const ListErrorCode = ({
onClick={handleNext}
disabled={pagination.current_page >= pagination.total_page}
size="small"
>
</Button>
></Button>
</div>
</Col>
</Row>
@@ -312,4 +331,4 @@ const ListErrorCode = ({
);
};
export default ListErrorCode;
export default ListErrorCode;

View File

@@ -44,16 +44,29 @@ import {
getNotificationDetail,
resendChatByUser,
resendChatAllUser,
searchData,
} from '../../../api/notification';
import { onNotifUpdate } from '../../../components/Global/MqttConnection';
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
const transformNotificationData = (apiData) => {
return apiData.map((item, index) => ({
id: `notification-${item.notification_error_id}-${index}`, // Unique key prefix with array index
type: item.is_read ? 'resolved' : item.is_delivered ? 'warning' : 'critical',
title: item.error_code_name || 'Unknown Error',
color: item.error_code_color || 'Black',
issue: item.error_code || item.error_code_name || 'Unknown Error',
description: `${item.error_code} - ${item.error_code_name || ''}`,
timestamp: item.created_at
@@ -89,6 +102,7 @@ const ListNotification = memo(function ListNotification(props) {
const [activeTab, setActiveTab] = useState('all');
const [searchTerm, setSearchTerm] = useState('');
const [searchValue, setSearchValue] = useState('');
const [notifTrigger, setNotifTrigger] = useState(0);
const [loading, setLoading] = useState(false);
const [modalContent, setModalContent] = useState(null); // 'user', 'log', 'details', or null
const [isAddingLog, setIsAddingLog] = useState(false);
@@ -166,6 +180,12 @@ const ListNotification = memo(function ListNotification(props) {
fetchNotifications(page, pageSize, isReadFilter);
};
useEffect(() => {
onNotifUpdate(() => {
setNotifTrigger((prev) => prev + 1);
});
}, []);
useEffect(() => {
const token = localStorage.getItem('token');
if (!token) {
@@ -176,18 +196,18 @@ const ListNotification = memo(function ListNotification(props) {
// Fetch notifications on component mount and when tab changes
const isReadFilter = activeTab === 'read' ? 1 : activeTab === 'unread' ? 0 : null;
fetchNotifications(pagination.current_page, pagination.current_limit, isReadFilter);
}, [activeTab]);
}, [activeTab, notifTrigger]);
const getIconAndColor = (type) => {
switch (type) {
case 'critical':
return { IconComponent: CloseCircleFilled, color: '#ff4d4f', bgColor: '#fff1f0' };
return { IconComponent: MailOutlined, color: '#faad14', bgColor: '#fff1f0' };
case 'warning':
return { IconComponent: WarningFilled, color: '#faad14', bgColor: '#fffbe6' };
return { IconComponent: MailOutlined, color: '#1890ff', bgColor: '#fffbe6' };
case 'resolved':
return { IconComponent: CheckCircleFilled, color: '#52c41a', bgColor: '#f6ffed' };
return { IconComponent: MailOutlined, color: '#52c41a', bgColor: '#f6ffed' };
default:
return { IconComponent: InfoCircleFilled, color: '#1890ff', bgColor: '#e6f7ff' };
return { IconComponent: MailOutlined, color: '#1890ff', bgColor: '#e6f7ff' };
}
};
@@ -219,13 +239,49 @@ 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 = () => {
setSearchTerm(searchValue);
fetchSearch(searchValue);
};
const handleSearchClear = () => {
setSearchValue('');
setSearchTerm('');
fetchSearch('');
};
const getUnreadCount = () => notifications.filter((n) => !n.isRead).length;
@@ -368,7 +424,11 @@ const ListNotification = memo(function ListNotification(props) {
flexShrink: 0,
}}
>
<IconComponent style={{ fontSize: '22px' }} />
{notification.type === 'resolved' ? (
<OpenMail size={28.5} color={color} />
) : (
<IconComponent style={{ fontSize: '22px' }} />
)}
</div>
<div style={{ flex: 1 }}>
<Row align="top">
@@ -383,8 +443,12 @@ const ListNotification = memo(function ListNotification(props) {
<div>
<Text strong>{notification.title}</Text>
<div style={{ marginTop: '4px' }}>
<Text style={{ color }}>
{notification.issue}
<Text
style={{
color: notification.color,
}}
>
Error Code {notification.issue}
</Text>
</div>
</div>
@@ -697,8 +761,8 @@ const ListNotification = memo(function ListNotification(props) {
{/* Kolom Kanan: Card */}
<Col flex="auto">
<Card size="small" style={{ borderColor: '#91d5ff' }}>
<Row gutter={[16, 8]} align="middle">
<Col xs={24} md={12}>
<Row gutter={[16, 8]} align="top">
<Col xs={24} md={10}>
<Space direction="vertical" size={4}>
<Space>
<ClockCircleOutlined />
@@ -709,13 +773,14 @@ const ListNotification = memo(function ListNotification(props) {
Added at {log.timestamp}
</Text>
</Space>
<div>
<Text strong>{log.addedBy.name}</Text>
</div>
<div>
<Text strong>
Added by: {log.addedBy.name}
</Text>
<span
style={{
marginLeft: '8px',
border: '1px solid #52c41a',
color: '#52c41a',
padding: '2px 6px',
@@ -728,7 +793,8 @@ const ListNotification = memo(function ListNotification(props) {
</div>
</Space>
</Col>
<Col xs={24} md={12}>
<Col xs={24} md={14}>
<Text strong>Description:</Text>
<Paragraph
style={{
color: '#595959',

View File

@@ -394,7 +394,7 @@ const NotificationDetailTab = (props) => {
<Text>{notification.title}</Text>
<div style={{ marginTop: '2px' }}>
<Text strong style={{ fontSize: '16px' }}>
{notification.issue}
Error Code {notification.issue}
</Text>
</div>
</Col>
@@ -542,393 +542,407 @@ const NotificationDetailTab = (props) => {
</Col>
</Row>
<Row gutter={[8, 8]} style={{ marginBottom: 'px' }}>
<Row gutter={[8, 8]}>
<Col xs={24} md={8}>
<Card
hoverable
bodyStyle={{ padding: '12px', textAlign: 'center' }}
>
<Space>
<BookOutlined
style={{ fontSize: '16px', color: '#1890ff' }}
/>
<Text strong style={{ fontSize: '16px', color: '#262626' }}>
Handling Guideline
</Text>
</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
direction="vertical"
size="small"
style={{ width: '100%' }}
<div>
<Card
hoverable
bodyStyle={{ padding: '12px'}}
>
{notification.error_code?.solution &&
notification.error_code.solution.length > 0 ? (
<>
{notification.error_code.solution
.filter((sol) => sol.is_active) // Hanya tampilkan solusi yang aktif
.map((sol, index) => (
<div
key={
sol.brand_code_solution_id || index
}
>
{sol.path_document ? (
<Card
size="small"
bodyStyle={{
padding: '8px 12px',
marginBottom: '4px',
}}
hoverable
extra={
<Text
type="secondary"
style={{
fontSize: '10px',
}}
>
PDF
</Text>
}
>
<div
style={{
display: 'flex',
justifyContent:
'space-between',
alignItems: 'center',
<Space>
<BookOutlined
style={{ fontSize: '16px', color: '#1890ff' }}
/>
<Text
strong
style={{ fontSize: '16px', color: '#262626' }}
>
Handling Guideline
</Text>
</Space>
<Space
direction="vertical"
size="small"
style={{ width: '100%' }}
>
{notification.error_code?.solution &&
notification.error_code.solution.length > 0 ? (
<>
{notification.error_code.solution
.filter((sol) => sol.is_active) // Hanya tampilkan solusi yang aktif
.map((sol, index) => (
<div
key={
sol.brand_code_solution_id ||
index
}
>
{sol.path_document ? (
<Card
size="small"
bodyStyle={{
padding: '8px 12px',
marginBottom: '4px',
}}
>
<div>
hoverable
extra={
<Text
type="secondary"
style={{
fontSize:
'12px',
color: '#262626',
'10px',
}}
>
<FilePdfOutlined
style={{
marginRight:
'8px',
}}
/>{' '}
{sol.file_upload_name ||
'Solution Document.pdf'}
PDF
</Text>
<Link
href={sol.path_document.replace(
'/detail-notification/pdf/',
'/notification-detail/pdf/'
)}
target="_blank"
style={{
fontSize:
'12px',
display:
'block',
}}
>
lihat disini
</Link>
</div>
</div>
</Card>
) : null}
{sol.type_solution === 'text' &&
sol.text_solution ? (
<Card
size="small"
bodyStyle={{
padding: '8px 12px',
marginBottom: '4px',
}}
extra={
<Text
type="secondary"
style={{
fontSize: '10px',
}}
>
{sol.type_solution.toUpperCase()}
</Text>
}
>
<div>
<Text strong>
{sol.solution_name}:
</Text>
}
>
<div
style={{
marginTop: '4px',
display: 'flex',
justifyContent:
'space-between',
alignItems:
'center',
}}
>
{sol.text_solution}
<div>
<Text
style={{
fontSize:
'12px',
color: '#262626',
}}
>
<FilePdfOutlined
style={{
marginRight:
'8px',
}}
/>{' '}
{sol.file_upload_name ||
'Solution Document.pdf'}
</Text>
<Link
href={sol.path_document.replace(
'/detail-notification/pdf/',
'/notification-detail/pdf/'
)}
target="_blank"
style={{
fontSize:
'12px',
display:
'block',
}}
>
lihat disini
</Link>
</div>
</div>
</div>
</Card>
) : null}
</div>
))}
</>
) : (
<div
style={{
textAlign: 'center',
padding: '20px',
color: '#8c8c8c',
}}
>
Tidak ada dokumen solusi tersedia
</div>
)}
</Space>
</Card>
</Card>
) : null}
{sol.type_solution === 'text' &&
sol.text_solution ? (
<Card
size="small"
title={
<Text strong>
{sol.solution_name}:
</Text>
}
bodyStyle={{
padding: '8px 12px',
marginBottom: '4px',
}}
extra={
<Text
type="secondary"
style={{
fontSize:
'10px',
}}
>
{sol.type_solution.toUpperCase()}
</Text>
}
>
<div>
<div
style={{
marginTop:
'4px',
}}
>
{sol.text_solution}
</div>
</div>
</Card>
) : null}
</div>
))}
</>
) : (
<div
style={{
textAlign: 'center',
padding: '20px',
color: '#8c8c8c',
}}
>
Tidak ada dokumen solusi tersedia
</div>
)}
</Space>
</Card>
</div>
</Col>
<Col xs={24} md={8}>
<Card
size="small"
title="Required Spare Parts"
style={{ height: '100%' }}
>
<Space
direction="vertical"
size="small"
style={{ width: '100%' }}
<div>
<Card
hoverable
bodyStyle={{ padding: '12px'}}
>
{notification.spareparts &&
notification.spareparts.length > 0 ? (
notification.spareparts.map((sparepart, index) => (
<Card
size="small"
key={index}
bodyStyle={{ padding: '12px' }}
hoverable
>
<Row gutter={16} align="top">
<Col
span={7}
style={{ textAlign: 'center' }}
>
<div
style={{
width: '100%',
height: '60px',
backgroundColor: '#f0f0f0',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '4px',
marginBottom: '8px',
}}
<Space>
<ToolOutlined
style={{ fontSize: '16px', color: '#1890ff' }}
/>
<Text
strong
style={{ fontSize: '16px', color: '#262626' }}
>
Spare Part
</Text>
</Space>
<Space
direction="vertical"
size="small"
style={{ width: '100%' }}
>
{notification.spareparts &&
notification.spareparts.length > 0 ? (
notification.spareparts.map((sparepart, index) => (
<Card
size="small"
key={index}
bodyStyle={{ padding: '12px' }}
hoverable
>
<Row gutter={16} align="top">
<Col
span={7}
style={{ textAlign: 'center' }}
>
<ToolOutlined
style={{
fontSize: '24px',
color: '#bfbfbf',
}}
/>
</div>
<Text
style={{
fontSize: '12px',
color:
sparepart.sparepart_stok ===
'Available' ||
sparepart.sparepart_stok ===
'available'
? '#52c41a'
: '#ff4d4f',
fontWeight: 500,
}}
>
{sparepart.sparepart_stok}
</Text>
</Col>
<Col span={17}>
<Space
direction="vertical"
size={4}
style={{ width: '100%' }}
>
<Text strong>
{sparepart.sparepart_name}
</Text>
<Paragraph
style={{
fontSize: '12px',
margin: 0,
color: '#595959',
}}
>
{sparepart.sparepart_description ||
'Deskripsi tidak tersedia'}
</Paragraph>
<div
style={{
border: '1px solid #d9d9d9',
width: '100%',
height: '60px',
backgroundColor: '#f0f0f0',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '4px',
padding: '4px 8px',
fontSize: '11px',
color: '#8c8c8c',
marginTop: '8px',
marginBottom: '8px',
}}
>
Kode: {sparepart.sparepart_code}{' '}
| Qty: {sparepart.sparepart_qty}{' '}
| Unit:{' '}
{sparepart.sparepart_unit}
<ToolOutlined
style={{
fontSize: '24px',
color: '#bfbfbf',
}}
/>
</div>
</Space>
</Col>
</Row>
</Card>
))
) : (
<div
style={{
textAlign: 'center',
padding: '20px',
color: '#8c8c8c',
}}
>
Tidak ada spare parts terkait
</div>
)}
</Space>
</Card>
<Text
style={{
fontSize: '12px',
color:
sparepart.sparepart_stok ===
'Available' ||
sparepart.sparepart_stok ===
'available'
? '#52c41a'
: '#ff4d4f',
fontWeight: 500,
}}
>
{sparepart.sparepart_stok}
</Text>
</Col>
<Col span={17}>
<Space
direction="vertical"
size={4}
style={{ width: '100%' }}
>
<Text strong>
{sparepart.sparepart_name}
</Text>
<Paragraph
style={{
fontSize: '12px',
margin: 0,
color: '#595959',
}}
>
{sparepart.sparepart_description ||
'Deskripsi tidak tersedia'}
</Paragraph>
<div
style={{
border: '1px solid #d9d9d9',
borderRadius: '4px',
padding: '4px 8px',
fontSize: '11px',
color: '#8c8c8c',
marginTop: '8px',
}}
>
Kode:{' '}
{sparepart.sparepart_code} |
Qty:{' '}
{sparepart.sparepart_qty} |
Unit:{' '}
{sparepart.sparepart_unit}
</div>
</Space>
</Col>
</Row>
</Card>
))
) : (
<div
style={{
textAlign: 'center',
padding: '20px',
color: '#8c8c8c',
}}
>
Tidak ada spare parts terkait
</div>
)}
</Space>
</Card>
</div>
</Col>
<Col xs={24} md={8}>
<Card size="small" style={{ height: '100%' }}>
<Space
direction="vertical"
size="small"
style={{ width: '100%' }}
>
<Card
size="small"
bodyStyle={{
padding: '8px 12px',
backgroundColor: isAddingLog ? '#fafafa' : '#fff',
}}
>
<Space
direction="vertical"
style={{ width: '100%' }}
size="small"
<div>
<Card bodyStyle={{ padding: '12px'}}>
<Space>
<HistoryOutlined
style={{ fontSize: '16px', color: '#1890ff' }}
/>
<Text
strong
style={{ fontSize: '16px', color: '#262626' }}
>
{isAddingLog && (
<>
<Text strong style={{ fontSize: '12px' }}>
Add New Log / Update Progress
</Text>
<Input.TextArea
rows={2}
placeholder="Tuliskan update penanganan di sini..."
value={newLogDescription}
onChange={(e) =>
setNewLogDescription(e.target.value)
}
disabled={submitLoading}
/>
</>
)}
<Button
type={isAddingLog ? 'primary' : 'dashed'}
size="small"
block
icon={
submitLoading ? (
<LoadingOutlined />
) : (
!isAddingLog && <PlusOutlined />
)
}
onClick={
isAddingLog
? handleSubmitLog
: () => setIsAddingLog(true)
}
loading={submitLoading}
disabled={submitLoading}
>
{isAddingLog ? 'Submit Log' : 'Add Log'}
</Button>
{isAddingLog && (
<Button
size="small"
block
onClick={() => {
setIsAddingLog(false);
setNewLogDescription('');
}}
disabled={submitLoading}
>
Cancel
</Button>
)}
</Space>
</Card>
{logHistoryData.map((log) => (
Log Activity
</Text>
</Space>
<Space
direction="vertical"
size="small"
style={{ width: '100%' }}
>
<Card
key={log.id}
size="small"
bodyStyle={{
padding: '8px 12px',
backgroundColor: isAddingLog
? '#fafafa'
: '#fff',
}}
>
<Paragraph
style={{ fontSize: '12px', margin: 0 }}
ellipsis={{ rows: 2 }}
<Space
direction="vertical"
style={{ width: '100%' }}
size="small"
>
<Text strong>{log.addedBy.name}:</Text>{' '}
{log.description}
</Paragraph>
<Text type="secondary" style={{ fontSize: '11px' }}>
{log.timestamp}
</Text>
{isAddingLog && (
<>
<Text
strong
style={{ fontSize: '12px' }}
>
Add New Log / Update Progress
</Text>
<Input.TextArea
rows={2}
placeholder="Tuliskan update penanganan di sini..."
value={newLogDescription}
onChange={(e) =>
setNewLogDescription(
e.target.value
)
}
disabled={submitLoading}
/>
</>
)}
<Button
type={isAddingLog ? 'primary' : 'dashed'}
size="small"
block
icon={
submitLoading ? (
<LoadingOutlined />
) : (
!isAddingLog && <PlusOutlined />
)
}
onClick={
isAddingLog
? handleSubmitLog
: () => setIsAddingLog(true)
}
loading={submitLoading}
disabled={submitLoading}
>
{isAddingLog ? 'Submit Log' : 'Add Log'}
</Button>
{isAddingLog && (
<Button
size="small"
block
onClick={() => {
setIsAddingLog(false);
setNewLogDescription('');
}}
disabled={submitLoading}
>
Cancel
</Button>
)}
</Space>
</Card>
))}
</Space>
</Card>
{logHistoryData.map((log) => (
<Card
key={log.id}
size="small"
bodyStyle={{
padding: '8px 12px',
}}
>
<Paragraph
style={{ fontSize: '12px', margin: 0 }}
// ellipsis={{ rows: 2 }}
>
<Text strong>{log.addedBy.name}:</Text>{' '}
{log.description}
</Paragraph>
<Text
type="secondary"
style={{ fontSize: '11px' }}
>
{log.timestamp}
</Text>
</Card>
))}
</Space>
</Card>
</div>
</Col>
</Row>
</Space>

View File

@@ -0,0 +1,85 @@
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;

View File

@@ -0,0 +1,172 @@
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;