Compare commits
39 Commits
lavoce
...
5a7d64a05b
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a7d64a05b | |||
| e74b802a60 | |||
| f436865b7f | |||
| 48437c3c50 | |||
| 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_PASSWORD=
|
||||
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*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
*.config
|
||||
|
||||
node_modules
|
||||
dist
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "antd-vite-react-call-of-duty",
|
||||
"name": "antd-vite-react-sypiu",
|
||||
"homepage": "/dashboard/home",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host 0.0.0.0 --port 8592",
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -36,7 +36,6 @@ 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';
|
||||
|
||||
@@ -145,10 +144,6 @@ 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>
|
||||
|
||||
@@ -82,15 +82,6 @@ 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,
|
||||
@@ -101,5 +92,4 @@ export {
|
||||
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;"/>
|
||||
<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)"/>
|
||||
@@ -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;"/>
|
||||
<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;">
|
||||
@@ -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;"/>
|
||||
<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)" 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>
|
||||
<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, -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;"/>
|
||||
<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, -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);"/>
|
||||
<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);"/>
|
||||
@@ -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);"/>
|
||||
<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>
|
||||
@@ -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="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(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"/>
|
||||
<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"/>
|
||||
</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);"/>
|
||||
<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)" 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>
|
||||
<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, -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;"/>
|
||||
<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, 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);"/>
|
||||
<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>
|
||||
@@ -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);"/>
|
||||
<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>
|
||||
@@ -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="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.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="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="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"/>
|
||||
<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"/>
|
||||
</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);"/>
|
||||
<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)" 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>
|
||||
<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, -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;"/>
|
||||
<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, -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);"/>
|
||||
<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>
|
||||
@@ -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);"/>
|
||||
<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>
|
||||
@@ -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="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.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="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(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"/>
|
||||
<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"/>
|
||||
</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 |
@@ -10,8 +10,7 @@ const topics = [
|
||||
'PIU_COD/COMPRESSOR/OVERVIEW',
|
||||
'PIU_COD/COMPRESSOR/COMPRESSOR_A',
|
||||
'PIU_COD/COMPRESSOR/COMPRESSOR_B',
|
||||
'PIU_COD/COMPRESSOR/COMPRESSOR_C',
|
||||
'PIU_COD/ERROR_CODE/SIM',
|
||||
'PIU_COD/COMPRESSOR/COMPRESSOR_C'
|
||||
];
|
||||
const options = {
|
||||
keepalive: 30,
|
||||
@@ -74,97 +73,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) => {
|
||||
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) 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);
|
||||
if (el) {
|
||||
if (value === true) {
|
||||
el.style.display = ''; // sembunyikan
|
||||
} else if (value === false) {
|
||||
el.style.display = 'none';
|
||||
} else if (!isNaN(value)) {
|
||||
handleNumber(el, value);
|
||||
el.textContent = Number(value ?? 0.0).toFixed(2);
|
||||
} else {
|
||||
handleOther(el, value);
|
||||
el.textContent = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
const target = svg.querySelector('text[x="225.25"][y="537.752"]');
|
||||
if (target) target.remove();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// === 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 };
|
||||
export { publishMessage, listenMessage, setValSvg };
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
DatabaseOutlined,
|
||||
SettingOutlined,
|
||||
UserOutlined,
|
||||
GlobalOutlined,
|
||||
AntDesignOutlined,
|
||||
ShoppingCartOutlined,
|
||||
ShoppingOutlined,
|
||||
@@ -37,14 +36,6 @@ 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 = [
|
||||
{
|
||||
@@ -234,19 +225,6 @@ 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' }} />,
|
||||
@@ -272,7 +250,6 @@ 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';
|
||||
|
||||
@@ -26,7 +26,7 @@ export default function RedirectWa() {
|
||||
|
||||
console.log('tes', response);
|
||||
|
||||
const tokenResult = JSON.stringify(response.data?.data?.accessToken);
|
||||
const tokenResult = JSON.stringify(response.data?.accessToken);
|
||||
|
||||
sessionStorage.setItem('token_redirect', tokenResult);
|
||||
response.data.auth = true;
|
||||
|
||||
@@ -13,18 +13,13 @@ import {
|
||||
Space,
|
||||
ConfigProvider,
|
||||
} 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 { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
|
||||
import {
|
||||
getBrandById,
|
||||
createBrand,
|
||||
createErrorCode,
|
||||
getErrorCodesByBrandId,
|
||||
updateErrorCode,
|
||||
deleteErrorCode,
|
||||
deleteBrand,
|
||||
} from '../../../api/master-brand';
|
||||
import { getBrandById, createBrand, createErrorCode, getErrorCodesByBrandId, updateErrorCode, deleteErrorCode, deleteBrand } from '../../../api/master-brand';
|
||||
import BrandForm from './component/BrandForm';
|
||||
import ErrorCodeForm from './component/ErrorCodeForm';
|
||||
import SolutionForm from './component/SolutionForm';
|
||||
@@ -47,9 +42,7 @@ const AddBrandDevice = () => {
|
||||
const [selectedSparepartIds, setSelectedSparepartIds] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const tab = searchParams.get('tab');
|
||||
const [currentStep, setCurrentStep] = useState(
|
||||
tab === 'error-codes' ? 1 : location.state?.phase || 0
|
||||
);
|
||||
const [currentStep, setCurrentStep] = useState(tab === 'error-codes' ? 1 : (location.state?.phase || 0));
|
||||
const [editingErrorCodeKey, setEditingErrorCodeKey] = useState(null);
|
||||
const [isErrorCodeFormReadOnly, setIsErrorCodeFormReadOnly] = useState(false);
|
||||
const [searchText, setSearchText] = useState('');
|
||||
@@ -75,7 +68,7 @@ const AddBrandDevice = () => {
|
||||
const values = solutionForm.getFieldsValue(true);
|
||||
const solutions = [];
|
||||
|
||||
solutionFields.forEach((fieldKey) => {
|
||||
solutionFields.forEach(fieldKey => {
|
||||
let solution = null;
|
||||
|
||||
if (values.solution_items && values.solution_items[fieldKey]) {
|
||||
@@ -92,16 +85,9 @@ const AddBrandDevice = () => {
|
||||
if (solutionType === 'text') {
|
||||
isValid = solution.text && solution.text.trim() !== '';
|
||||
} else if (solutionType === 'file') {
|
||||
const hasPathSolution =
|
||||
solution.path_solution && solution.path_solution.trim() !== '';
|
||||
const hasFileUpload =
|
||||
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;
|
||||
const hasPathSolution = solution.path_solution && solution.path_solution.trim() !== '';
|
||||
const hasFileUpload = (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;
|
||||
}
|
||||
|
||||
@@ -132,9 +118,9 @@ const AddBrandDevice = () => {
|
||||
text: '',
|
||||
status: true,
|
||||
file: null,
|
||||
fileUpload: null,
|
||||
},
|
||||
},
|
||||
fileUpload: null
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
@@ -142,6 +128,7 @@ const AddBrandDevice = () => {
|
||||
};
|
||||
|
||||
const setSolutionsForExistingRecord = (solutions, targetForm) => {
|
||||
|
||||
if (!targetForm || !solutions || solutions.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -166,14 +153,11 @@ const AddBrandDevice = () => {
|
||||
fileObject = {
|
||||
uploadPath: solution.path_solution || solution.path_document,
|
||||
path_solution: solution.path_solution || solution.path_document,
|
||||
name:
|
||||
solution.file_upload_name ||
|
||||
(solution.path_solution || solution.path_document).split('/').pop() ||
|
||||
'File',
|
||||
name: solution.file_upload_name || (solution.path_solution || solution.path_document).split('/').pop() || 'File',
|
||||
type_solution: solution.type_solution,
|
||||
isExisting: true,
|
||||
size: 0,
|
||||
url: solution.path_solution || solution.path_document,
|
||||
url: solution.path_solution || solution.path_document
|
||||
};
|
||||
}
|
||||
|
||||
@@ -186,7 +170,7 @@ const AddBrandDevice = () => {
|
||||
file: fileObject,
|
||||
fileUpload: fileObject,
|
||||
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);
|
||||
|
||||
|
||||
targetForm.resetFields();
|
||||
|
||||
setTimeout(() => {
|
||||
targetForm.setFieldsValue({
|
||||
solution_items: solutionItems,
|
||||
solution_items: solutionItems
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
Object.keys(solutionItems).forEach((key) => {
|
||||
Object.keys(solutionItems).forEach(key => {
|
||||
const solution = solutionItems[key];
|
||||
targetForm.setFieldValue(['solution_items', key, 'name'], solution.name);
|
||||
targetForm.setFieldValue(['solution_items', key, 'type'], solution.type);
|
||||
targetForm.setFieldValue(['solution_items', key, 'text'], solution.text);
|
||||
targetForm.setFieldValue(['solution_items', key, 'file'], solution.file);
|
||||
targetForm.setFieldValue(
|
||||
['solution_items', key, 'fileUpload'],
|
||||
solution.fileUpload
|
||||
);
|
||||
targetForm.setFieldValue(['solution_items', key, 'fileUpload'], solution.fileUpload);
|
||||
targetForm.setFieldValue(['solution_items', key, 'status'], solution.status);
|
||||
targetForm.setFieldValue(
|
||||
['solution_items', key, 'path_solution'],
|
||||
solution.path_solution
|
||||
);
|
||||
targetForm.setFieldValue(
|
||||
['solution_items', key, 'fileName'],
|
||||
solution.fileName
|
||||
);
|
||||
targetForm.setFieldValue(['solution_items', key, 'path_solution'], solution.path_solution);
|
||||
targetForm.setFieldValue(['solution_items', key, 'fileName'], solution.fileName);
|
||||
});
|
||||
|
||||
|
||||
const finalValues = targetForm.getFieldsValue();
|
||||
}, 100);
|
||||
}, 100);
|
||||
@@ -232,14 +209,14 @@ const AddBrandDevice = () => {
|
||||
|
||||
const handleAddSolutionField = () => {
|
||||
const newKey = Math.max(...solutionFields, 0) + 1;
|
||||
setSolutionFields((prev) => [...prev, newKey]);
|
||||
setSolutionTypes((prev) => ({ ...prev, [newKey]: 'text' }));
|
||||
setSolutionStatuses((prev) => ({ ...prev, [newKey]: true }));
|
||||
setSolutionFields(prev => [...prev, newKey]);
|
||||
setSolutionTypes(prev => ({ ...prev, [newKey]: 'text' }));
|
||||
setSolutionStatuses(prev => ({ ...prev, [newKey]: true }));
|
||||
};
|
||||
|
||||
const handleRemoveSolutionField = (fieldKey) => {
|
||||
if (solutionFields.length > 1) {
|
||||
setSolutionFields((prev) => prev.filter((key) => key !== fieldKey));
|
||||
setSolutionFields(prev => prev.filter(key => key !== fieldKey));
|
||||
const newTypes = { ...solutionTypes };
|
||||
const newStatuses = { ...solutionStatuses };
|
||||
delete newTypes[fieldKey];
|
||||
@@ -256,7 +233,7 @@ const AddBrandDevice = () => {
|
||||
};
|
||||
|
||||
const handleSolutionTypeChange = (fieldKey, type) => {
|
||||
setSolutionTypes((prev) => ({ ...prev, [fieldKey]: type }));
|
||||
setSolutionTypes(prev => ({ ...prev, [fieldKey]: type }));
|
||||
|
||||
if (type === 'file') {
|
||||
solutionForm.setFieldValue(['solution_items', fieldKey, 'text'], '');
|
||||
@@ -269,7 +246,7 @@ const AddBrandDevice = () => {
|
||||
};
|
||||
|
||||
const handleSolutionStatusChange = (fieldKey, status) => {
|
||||
setSolutionStatuses((prev) => ({ ...prev, [fieldKey]: status }));
|
||||
setSolutionStatuses(prev => ({ ...prev, [fieldKey]: status }));
|
||||
};
|
||||
|
||||
const handleNextStep = async () => {
|
||||
@@ -282,7 +259,7 @@ const AddBrandDevice = () => {
|
||||
brand_type: brandValues.brand_type || '',
|
||||
brand_manufacture: brandValues.brand_manufacture || '',
|
||||
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);
|
||||
@@ -291,7 +268,7 @@ const AddBrandDevice = () => {
|
||||
const newBrandInfo = {
|
||||
...brandValues,
|
||||
brand_id: response.data.brand_id,
|
||||
brand_code: response.data.brand_code,
|
||||
brand_code: response.data.brand_code
|
||||
};
|
||||
setBrandInfo(newBrandInfo);
|
||||
setTemporaryBrandId(response.data.brand_id);
|
||||
@@ -330,7 +307,8 @@ const AddBrandDevice = () => {
|
||||
if (isTemporaryBrand && temporaryBrandId) {
|
||||
try {
|
||||
await deleteBrand(temporaryBrandId);
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
navigate('/master/brand-device');
|
||||
};
|
||||
@@ -382,6 +360,8 @@ const AddBrandDevice = () => {
|
||||
setTrigerFilter((prev) => !prev);
|
||||
};
|
||||
|
||||
|
||||
|
||||
const resetErrorCodeForm = () => {
|
||||
errorCodeForm.resetFields();
|
||||
errorCodeForm.setFieldsValue({
|
||||
@@ -411,16 +391,16 @@ const AddBrandDevice = () => {
|
||||
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 formattedSolutions = solutionData.map(solution => {
|
||||
const solutionType = solution.type || 'text';
|
||||
|
||||
let typeSolution = solutionType === 'text' ? 'text' : 'image';
|
||||
@@ -442,11 +422,7 @@ const AddBrandDevice = () => {
|
||||
} else {
|
||||
formattedSolution.text_solution = '';
|
||||
|
||||
formattedSolution.path_solution =
|
||||
solution.path_solution ||
|
||||
solution.file?.uploadPath ||
|
||||
solution.fileUpload?.uploadPath ||
|
||||
'';
|
||||
formattedSolution.path_solution = solution.path_solution || solution.file?.uploadPath || solution.fileUpload?.uploadPath || '';
|
||||
}
|
||||
|
||||
if (formattedSolution.brand_code_solution_id) {
|
||||
@@ -464,7 +440,7 @@ const AddBrandDevice = () => {
|
||||
path_icon: errorCodeIcon?.uploadPath || '',
|
||||
is_active: errorCodeValues.status === undefined ? true : errorCodeValues.status,
|
||||
solution: formattedSolutions,
|
||||
spareparts: selectedSparepartIds || [],
|
||||
spareparts: selectedSparepartIds || []
|
||||
};
|
||||
|
||||
let response;
|
||||
@@ -480,13 +456,11 @@ const AddBrandDevice = () => {
|
||||
NotifOk({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
message: editingErrorCodeKey
|
||||
? 'Error code berhasil diupdate!'
|
||||
: 'Error code berhasil ditambahkan!',
|
||||
message: editingErrorCodeKey ? 'Error code berhasil diupdate!' : 'Error code berhasil ditambahkan!',
|
||||
});
|
||||
|
||||
resetErrorCodeForm();
|
||||
setTrigerFilter((prev) => !prev);
|
||||
setTrigerFilter(prev => !prev);
|
||||
} else {
|
||||
NotifAlert({
|
||||
icon: 'error',
|
||||
@@ -505,10 +479,12 @@ const AddBrandDevice = () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleErrorCodeIconRemove = () => {
|
||||
setErrorCodeIcon(null);
|
||||
};
|
||||
|
||||
|
||||
const handleFinish = async () => {
|
||||
setConfirmLoading(true);
|
||||
try {
|
||||
@@ -530,10 +506,10 @@ const AddBrandDevice = () => {
|
||||
const response = await getErrorCodesByBrandId(brandInfo.brand_id, queryParams);
|
||||
|
||||
if (response && response.statusCode === 200 && response.data) {
|
||||
const freshErrorCodes = response.data.map((ec) => ({
|
||||
const freshErrorCodes = response.data.map(ec => ({
|
||||
...ec,
|
||||
tempId: `existing_${ec.error_code_id}`,
|
||||
status: 'existing',
|
||||
status: 'existing'
|
||||
}));
|
||||
setApiErrorCodes(freshErrorCodes);
|
||||
|
||||
@@ -541,8 +517,7 @@ const AddBrandDevice = () => {
|
||||
NotifAlert({
|
||||
icon: 'warning',
|
||||
title: 'Perhatian',
|
||||
message:
|
||||
'Harap tambahkan minimal 1 error code sebelum menyelesaikan.',
|
||||
message: 'Harap tambahkan minimal 1 error code sebelum menyelesaikan.',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -551,8 +526,7 @@ const AddBrandDevice = () => {
|
||||
NotifAlert({
|
||||
icon: 'warning',
|
||||
title: 'Perhatian',
|
||||
message:
|
||||
'Harap tambahkan minimal 1 error code sebelum menyelesaikan.',
|
||||
message: 'Harap tambahkan minimal 1 error code sebelum menyelesaikan.',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -617,7 +591,11 @@ const AddBrandDevice = () => {
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
)}
|
||||
<BrandForm form={brandForm} isEdit={false} brandInfo={brandInfo} />
|
||||
<BrandForm
|
||||
form={brandForm}
|
||||
isEdit={false}
|
||||
brandInfo={brandInfo}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -657,39 +635,31 @@ const AddBrandDevice = () => {
|
||||
</Col>
|
||||
|
||||
<Col xs={24} md={16} lg={16}>
|
||||
<div
|
||||
style={{
|
||||
paddingLeft: '12px',
|
||||
}}
|
||||
>
|
||||
<div style={{
|
||||
paddingLeft: '12px'
|
||||
}}>
|
||||
<Card
|
||||
title={
|
||||
<div
|
||||
style={{
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
width: '100%'
|
||||
}}>
|
||||
<span style={{
|
||||
fontSize: '16px',
|
||||
fontWeight: '600',
|
||||
color: '#262626',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px',
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
gap: '8px'
|
||||
}}>
|
||||
<span style={{
|
||||
width: '4px',
|
||||
height: '20px',
|
||||
backgroundColor: '#23A55A',
|
||||
borderRadius: '2px',
|
||||
}}
|
||||
></span>
|
||||
borderRadius: '2px'
|
||||
}}></span>
|
||||
Error Code Form
|
||||
</span>
|
||||
<Button
|
||||
@@ -705,51 +675,43 @@ const AddBrandDevice = () => {
|
||||
padding: '0 24px',
|
||||
fontWeight: '500',
|
||||
boxShadow: '0 2px 4px rgba(35, 165, 90, 0.2)',
|
||||
transition: 'all 0.3s ease',
|
||||
transition: 'all 0.3s ease'
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.target.style.boxShadow =
|
||||
'0 4px 8px rgba(35, 165, 90, 0.3)';
|
||||
e.target.style.boxShadow = '0 4px 8px rgba(35, 165, 90, 0.3)';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.target.style.boxShadow =
|
||||
'0 2px 4px rgba(35, 165, 90, 0.2)';
|
||||
e.target.style.boxShadow = '0 2px 4px rgba(35, 165, 90, 0.2)';
|
||||
}}
|
||||
>
|
||||
{editingErrorCodeKey
|
||||
? 'Update Error Code'
|
||||
: 'Save Error Code'}
|
||||
{editingErrorCodeKey ? 'Update Error Code' : 'Save Error Code'}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
style={{
|
||||
width: '100%',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.06)',
|
||||
borderRadius: '12px',
|
||||
borderRadius: '12px'
|
||||
}}
|
||||
styles={{
|
||||
body: { padding: '16px 24px 12px 24px' },
|
||||
header: {
|
||||
padding: '16px 24px',
|
||||
borderBottom: '1px solid #f0f0f0',
|
||||
backgroundColor: '#fafafa',
|
||||
},
|
||||
backgroundColor: '#fafafa'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
||||
<div style={{
|
||||
padding: '16px',
|
||||
border: '1px solid #f0f0f0',
|
||||
borderRadius: '10px',
|
||||
backgroundColor: '#ffffff',
|
||||
marginBottom: '0',
|
||||
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}
|
||||
isErrorCodeFormReadOnly={isErrorCodeFormReadOnly}
|
||||
@@ -762,42 +724,29 @@ const AddBrandDevice = () => {
|
||||
|
||||
<Row gutter={[20, 0]} style={{ marginTop: '0' }}>
|
||||
<Col xs={24} md={12} lg={12}>
|
||||
<div
|
||||
style={{
|
||||
<div style={{
|
||||
padding: '16px',
|
||||
border: '1px solid #f0f0f0',
|
||||
borderRadius: '10px',
|
||||
backgroundColor: '#ffffff',
|
||||
transition: 'all 0.3s ease',
|
||||
boxShadow: '0 1px 3px rgba(0,0,0,0.04)',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
boxShadow: '0 1px 3px rgba(0,0,0,0.04)'
|
||||
}}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px',
|
||||
marginBottom: '12px',
|
||||
paddingBottom: '8px',
|
||||
borderBottom: '1px solid #f5f5f5',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
borderBottom: '1px solid #f5f5f5'
|
||||
}}>
|
||||
<div style={{
|
||||
width: '3px',
|
||||
height: '16px',
|
||||
backgroundColor: '#1890ff',
|
||||
borderRadius: '2px',
|
||||
}}
|
||||
></div>
|
||||
<h4
|
||||
style={{
|
||||
margin: 0,
|
||||
color: '#262626',
|
||||
fontSize: '14px',
|
||||
fontWeight: '600',
|
||||
}}
|
||||
>
|
||||
borderRadius: '2px'
|
||||
}}></div>
|
||||
<h4 style={{ margin: 0, color: '#262626', fontSize: '14px', fontWeight: '600' }}>
|
||||
Solution
|
||||
</h4>
|
||||
</div>
|
||||
@@ -807,23 +756,14 @@ const AddBrandDevice = () => {
|
||||
solutionTypes={solutionTypes}
|
||||
solutionStatuses={solutionStatuses}
|
||||
onAddSolutionField={handleAddSolutionField}
|
||||
onRemoveSolutionField={
|
||||
handleRemoveSolutionField
|
||||
}
|
||||
onRemoveSolutionField={handleRemoveSolutionField}
|
||||
onSolutionTypeChange={handleSolutionTypeChange}
|
||||
onSolutionStatusChange={
|
||||
handleSolutionStatusChange
|
||||
}
|
||||
onSolutionFileUpload={(fileData) => {}}
|
||||
onSolutionStatusChange={handleSolutionStatusChange}
|
||||
onSolutionFileUpload={(fileData) => {
|
||||
}}
|
||||
onFileView={(fileData) => {
|
||||
if (
|
||||
fileData &&
|
||||
(fileData.url || fileData.uploadPath)
|
||||
) {
|
||||
window.open(
|
||||
fileData.url || fileData.uploadPath,
|
||||
'_blank'
|
||||
);
|
||||
if (fileData && (fileData.url || fileData.uploadPath)) {
|
||||
window.open(fileData.url || fileData.uploadPath, '_blank');
|
||||
}
|
||||
}}
|
||||
isReadOnly={false}
|
||||
@@ -832,55 +772,40 @@ const AddBrandDevice = () => {
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} md={12} lg={12}>
|
||||
<div
|
||||
style={{
|
||||
<div style={{
|
||||
padding: '16px',
|
||||
border: '1px solid #f0f0f0',
|
||||
borderRadius: '10px',
|
||||
backgroundColor: '#ffffff',
|
||||
transition: 'all 0.3s ease',
|
||||
boxShadow: '0 1px 3px rgba(0,0,0,0.04)',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
boxShadow: '0 1px 3px rgba(0,0,0,0.04)'
|
||||
}}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px',
|
||||
marginBottom: '12px',
|
||||
paddingBottom: '8px',
|
||||
borderBottom: '1px solid #f5f5f5',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
borderBottom: '1px solid #f5f5f5'
|
||||
}}>
|
||||
<div style={{
|
||||
width: '3px',
|
||||
height: '16px',
|
||||
backgroundColor: '#faad14',
|
||||
borderRadius: '2px',
|
||||
}}
|
||||
></div>
|
||||
<h4
|
||||
style={{
|
||||
margin: 0,
|
||||
color: '#262626',
|
||||
fontSize: '14px',
|
||||
fontWeight: '600',
|
||||
}}
|
||||
>
|
||||
borderRadius: '2px'
|
||||
}}></div>
|
||||
<h4 style={{ margin: 0, color: '#262626', fontSize: '14px', fontWeight: '600' }}>
|
||||
Sparepart Selection
|
||||
</h4>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
<div style={{
|
||||
maxHeight: '45vh',
|
||||
overflow: 'auto',
|
||||
border: '1px solid #e8e8e8',
|
||||
borderRadius: '8px',
|
||||
padding: '12px',
|
||||
backgroundColor: '#fafafa',
|
||||
}}
|
||||
>
|
||||
backgroundColor: '#fafafa'
|
||||
}}>
|
||||
<SparepartSelect
|
||||
selectedSparepartIds={selectedSparepartIds}
|
||||
onSparepartChange={setSelectedSparepartIds}
|
||||
@@ -891,16 +816,15 @@ const AddBrandDevice = () => {
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<div
|
||||
style={{
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: '16px 0 0 0',
|
||||
borderTop: '1px solid #f0f0f0',
|
||||
marginTop: '12px',
|
||||
}}
|
||||
>
|
||||
marginTop: '12px'
|
||||
}}>
|
||||
|
||||
{editingErrorCodeKey && (
|
||||
<Button
|
||||
size="large"
|
||||
@@ -913,7 +837,7 @@ const AddBrandDevice = () => {
|
||||
height: '40px',
|
||||
padding: '0 24px',
|
||||
fontWeight: '500',
|
||||
transition: 'all 0.3s ease',
|
||||
transition: 'all 0.3s ease'
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.target.style.borderColor = '#ff4d4f';
|
||||
@@ -947,7 +871,7 @@ const AddBrandDevice = () => {
|
||||
|
||||
setBreadcrumbItems([
|
||||
{
|
||||
title: <span style={{ fontSize: '14px', fontWeight: 'bold' }}>• Master</span>,
|
||||
title: <span style={{ fontSize: '14px', fontWeight: 'bold' }}>• Master</span>
|
||||
},
|
||||
{
|
||||
title: (
|
||||
@@ -971,11 +895,12 @@ const AddBrandDevice = () => {
|
||||
if (location.state?.fromFileViewer && location.state.phase !== undefined) {
|
||||
setCurrentStep(location.state.phase);
|
||||
}
|
||||
|
||||
}, [setBreadcrumbItems, navigate, searchParams, location.state]);
|
||||
|
||||
useEffect(() => {
|
||||
if (brandInfo.brand_id && currentStep === 1) {
|
||||
setTrigerFilter((prev) => !prev);
|
||||
setTrigerFilter(prev => !prev);
|
||||
}
|
||||
}, [brandInfo.brand_id, currentStep]);
|
||||
|
||||
@@ -988,7 +913,8 @@ const AddBrandDevice = () => {
|
||||
const errorCodes = response.data || [];
|
||||
setApiErrorCodes(errorCodes);
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
};
|
||||
fetchErrorCodes();
|
||||
@@ -999,7 +925,8 @@ const AddBrandDevice = () => {
|
||||
if (isTemporaryBrand && temporaryBrandId && currentStep === 0) {
|
||||
try {
|
||||
await deleteBrand(temporaryBrandId);
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1010,6 +937,7 @@ const AddBrandDevice = () => {
|
||||
};
|
||||
}, [isTemporaryBrand, temporaryBrandId, currentStep]);
|
||||
|
||||
|
||||
return (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
@@ -1060,9 +988,14 @@ const AddBrandDevice = () => {
|
||||
<Divider />
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<div>
|
||||
<Button onClick={handleCancel}>Cancel</Button>
|
||||
<Button onClick={handleCancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
{currentStep === 1 && (
|
||||
<Button onClick={handlePrevStep} style={{ marginLeft: 8 }}>
|
||||
<Button
|
||||
onClick={handlePrevStep}
|
||||
style={{ marginLeft: 8 }}
|
||||
>
|
||||
Kembali ke Brand Info
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
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';
|
||||
|
||||
@@ -22,7 +16,7 @@ const ListErrorCode = ({
|
||||
onSearch,
|
||||
onSearchClear,
|
||||
isReadOnly = false,
|
||||
errorCodes: propErrorCodes = null,
|
||||
errorCodes: propErrorCodes = null
|
||||
}) => {
|
||||
const [errorCodes, setErrorCodes] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -58,12 +52,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);
|
||||
@@ -88,9 +82,11 @@ const ListErrorCode = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (isReadOnly && propErrorCodes) {
|
||||
|
||||
setErrorCodes(propErrorCodes);
|
||||
setLoading(false);
|
||||
} else {
|
||||
|
||||
fetchErrorCodes();
|
||||
}
|
||||
}, [brandId, queryParams, tempErrorCodes, trigerFilter, isReadOnly, propErrorCodes]);
|
||||
@@ -130,19 +126,20 @@ 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;
|
||||
}
|
||||
@@ -151,7 +148,7 @@ const ListErrorCode = ({
|
||||
NotifAlert({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
message: 'Brand ID tidak valid',
|
||||
message: 'Brand ID tidak valid'
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -162,21 +159,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'
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -184,8 +181,8 @@ const ListErrorCode = ({
|
||||
return (
|
||||
<Card
|
||||
title="Daftar Error Code"
|
||||
style={{ width: '100%', minWidth: '300px' }}
|
||||
bodyStyle={{ padding: '12px' }}
|
||||
style={{ width: '100%', minWidth: '472px' }}
|
||||
styles={{ body: { padding: '12px' } }}
|
||||
>
|
||||
<Input.Search
|
||||
placeholder="Cari error code..."
|
||||
@@ -206,7 +203,7 @@ const ListErrorCode = ({
|
||||
style={{
|
||||
backgroundColor: '#23A55A',
|
||||
borderColor: '#23A55A',
|
||||
height: '32px',
|
||||
height: '32px'
|
||||
}}
|
||||
>
|
||||
Search
|
||||
@@ -220,18 +217,19 @@ const ListErrorCode = ({
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
<div style={{
|
||||
height: '90vh',
|
||||
border: '1px solid #d9d9d9',
|
||||
borderRadius: '6px',
|
||||
overflow: 'auto',
|
||||
marginBottom: 12,
|
||||
backgroundColor: '#fafafa',
|
||||
}}
|
||||
>
|
||||
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) => (
|
||||
@@ -242,25 +240,13 @@ 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}
|
||||
@@ -280,7 +266,7 @@ const ListErrorCode = ({
|
||||
padding: '2px 6px',
|
||||
height: '24px',
|
||||
fontSize: '11px',
|
||||
border: '1px solid #ff4d4f',
|
||||
border: '1px solid #ff4d4f'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -306,15 +292,9 @@ 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
|
||||
@@ -322,7 +302,8 @@ const ListErrorCode = ({
|
||||
onClick={handleNext}
|
||||
disabled={pagination.current_page >= pagination.total_page}
|
||||
size="small"
|
||||
></Button>
|
||||
>
|
||||
</Button>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@@ -44,29 +44,16 @@ 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
|
||||
@@ -102,7 +89,6 @@ 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);
|
||||
@@ -180,12 +166,6 @@ const ListNotification = memo(function ListNotification(props) {
|
||||
fetchNotifications(page, pageSize, isReadFilter);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
onNotifUpdate(() => {
|
||||
setNotifTrigger((prev) => prev + 1);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
@@ -196,18 +176,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, notifTrigger]);
|
||||
}, [activeTab]);
|
||||
|
||||
const getIconAndColor = (type) => {
|
||||
switch (type) {
|
||||
case 'critical':
|
||||
return { IconComponent: MailOutlined, color: '#faad14', bgColor: '#fff1f0' };
|
||||
return { IconComponent: CloseCircleFilled, color: '#ff4d4f', bgColor: '#fff1f0' };
|
||||
case 'warning':
|
||||
return { IconComponent: MailOutlined, color: '#1890ff', bgColor: '#fffbe6' };
|
||||
return { IconComponent: WarningFilled, color: '#faad14', bgColor: '#fffbe6' };
|
||||
case 'resolved':
|
||||
return { IconComponent: MailOutlined, color: '#52c41a', bgColor: '#f6ffed' };
|
||||
return { IconComponent: CheckCircleFilled, color: '#52c41a', bgColor: '#f6ffed' };
|
||||
default:
|
||||
return { IconComponent: MailOutlined, color: '#1890ff', bgColor: '#e6f7ff' };
|
||||
return { IconComponent: InfoCircleFilled, color: '#1890ff', bgColor: '#e6f7ff' };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -239,49 +219,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 = () => {
|
||||
fetchSearch(searchValue);
|
||||
setSearchTerm(searchValue);
|
||||
};
|
||||
|
||||
const handleSearchClear = () => {
|
||||
setSearchValue('');
|
||||
fetchSearch('');
|
||||
setSearchTerm('');
|
||||
};
|
||||
|
||||
const getUnreadCount = () => notifications.filter((n) => !n.isRead).length;
|
||||
@@ -344,16 +288,14 @@ const ListNotification = memo(function ListNotification(props) {
|
||||
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', {
|
||||
timestamp: user.created_at
|
||||
? new Date(user.created_at).toLocaleString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})
|
||||
.replace('.', ':') + ' WIB'
|
||||
}) + ' WIB'
|
||||
: 'N/A',
|
||||
}));
|
||||
setUserHistoryData(transformedUsers);
|
||||
@@ -424,11 +366,7 @@ const ListNotification = memo(function ListNotification(props) {
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
{notification.type === 'resolved' ? (
|
||||
<OpenMail size={28.5} color={color} />
|
||||
) : (
|
||||
<IconComponent style={{ fontSize: '22px' }} />
|
||||
)}
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Row align="top">
|
||||
@@ -443,12 +381,8 @@ const ListNotification = memo(function ListNotification(props) {
|
||||
<div>
|
||||
<Text strong>{notification.title}</Text>
|
||||
<div style={{ marginTop: '4px' }}>
|
||||
<Text
|
||||
style={{
|
||||
color: notification.color,
|
||||
}}
|
||||
>
|
||||
Error Code {notification.issue}
|
||||
<Text style={{ color }}>
|
||||
{notification.issue}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
@@ -676,6 +610,9 @@ const ListNotification = memo(function ListNotification(props) {
|
||||
icon={<SendOutlined />}
|
||||
onClick={async () => {
|
||||
await resendChatByUser(user.id, user.phone);
|
||||
// message.info(
|
||||
// 'Resend feature is not available yet. This feature is still under development.'
|
||||
// );
|
||||
}}
|
||||
>
|
||||
Resend
|
||||
@@ -761,8 +698,8 @@ const ListNotification = memo(function ListNotification(props) {
|
||||
{/* Kolom Kanan: Card */}
|
||||
<Col flex="auto">
|
||||
<Card size="small" style={{ borderColor: '#91d5ff' }}>
|
||||
<Row gutter={[16, 8]} align="top">
|
||||
<Col xs={24} md={10}>
|
||||
<Row gutter={[16, 8]} align="middle">
|
||||
<Col xs={24} md={12}>
|
||||
<Space direction="vertical" size={4}>
|
||||
<Space>
|
||||
<ClockCircleOutlined />
|
||||
@@ -773,14 +710,13 @@ 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',
|
||||
@@ -793,8 +729,7 @@ const ListNotification = memo(function ListNotification(props) {
|
||||
</div>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col xs={24} md={14}>
|
||||
<Text strong>Description:</Text>
|
||||
<Col xs={24} md={12}>
|
||||
<Paragraph
|
||||
style={{
|
||||
color: '#595959',
|
||||
|
||||
@@ -14,8 +14,6 @@ import {
|
||||
message,
|
||||
Avatar,
|
||||
Tag,
|
||||
Badge,
|
||||
Divider,
|
||||
} from 'antd';
|
||||
import {
|
||||
ArrowLeftOutlined,
|
||||
@@ -35,8 +33,6 @@ import {
|
||||
CheckCircleOutlined,
|
||||
SyncOutlined,
|
||||
SendOutlined,
|
||||
MobileOutlined,
|
||||
ClockCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import {
|
||||
getNotificationDetail,
|
||||
@@ -44,7 +40,6 @@ import {
|
||||
getNotificationLogByNotificationId,
|
||||
updateIsRead,
|
||||
resendNotificationToUser,
|
||||
resendChatByUser,
|
||||
} from '../../api/notification';
|
||||
|
||||
const { Content } = Layout;
|
||||
@@ -113,19 +108,8 @@ const getUsersFromNotification = (notification) => {
|
||||
id: user.notification_error_user_id.toString(),
|
||||
name: user.contact_name,
|
||||
phone: user.contact_phone,
|
||||
status: user.is_send ? 'Delivered' : 'Pending',
|
||||
status: user.is_send ? 'sent' : 'pending',
|
||||
loading: user.loading || false,
|
||||
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',
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -251,6 +235,8 @@ const NotificationDetailTab = (props) => {
|
||||
|
||||
// Fetch using the actual API
|
||||
const response = await getNotificationDetail(notificationId);
|
||||
// Fetch using the actual API
|
||||
const resUpdate = await updateIsRead(notificationId);
|
||||
|
||||
if (response && response.data) {
|
||||
const transformedData = transformNotificationData(response.data);
|
||||
@@ -258,9 +244,6 @@ const NotificationDetailTab = (props) => {
|
||||
|
||||
// Fetch log history
|
||||
fetchLogHistory(notificationId);
|
||||
|
||||
// Fetch using the actual API
|
||||
const resUpdate = await updateIsRead(notificationId);
|
||||
} else {
|
||||
throw new Error('Notification not found');
|
||||
}
|
||||
@@ -394,7 +377,7 @@ const NotificationDetailTab = (props) => {
|
||||
<Text>{notification.title}</Text>
|
||||
<div style={{ marginTop: '2px' }}>
|
||||
<Text strong style={{ fontSize: '16px' }}>
|
||||
Error Code {notification.issue}
|
||||
{notification.issue}
|
||||
</Text>
|
||||
</div>
|
||||
</Col>
|
||||
@@ -482,56 +465,137 @@ const NotificationDetailTab = (props) => {
|
||||
<Row align="middle" justify="space-between">
|
||||
<Col>
|
||||
<Space align="center">
|
||||
<Avatar
|
||||
size="large"
|
||||
icon={<UserOutlined />}
|
||||
/>
|
||||
<div>
|
||||
<Text strong>{user.name}</Text>
|
||||
<Text>|</Text>
|
||||
<Text>
|
||||
<MobileOutlined /> {user.phone}
|
||||
</Text>
|
||||
<Text>|</Text>
|
||||
<Badge
|
||||
status={
|
||||
user.status === 'Delivered'
|
||||
? 'success'
|
||||
: 'default'
|
||||
}
|
||||
text={user.status}
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '4px',
|
||||
}}
|
||||
>
|
||||
<PhoneOutlined
|
||||
style={{
|
||||
color: '#8c8c8c',
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
<Divider style={{ margin: '8px 0' }} />
|
||||
<Space align="center">
|
||||
{user.status === 'Delivered' ? (
|
||||
<CheckCircleFilled
|
||||
style={{ color: '#52c41a' }}
|
||||
/>
|
||||
) : (
|
||||
<ClockCircleOutlined
|
||||
style={{ color: '#faad14' }}
|
||||
/>
|
||||
)}
|
||||
<Text type="secondary">
|
||||
{user.status === 'Delivered'
|
||||
? 'Success Delivered at'
|
||||
: 'Status '}{' '}
|
||||
{user.timestamp}
|
||||
{user.phone}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col>
|
||||
<Col>
|
||||
<Space align="center" size="large">
|
||||
{getStatusTag(user.status)}
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
icon={<SendOutlined />}
|
||||
onClick={async () => {
|
||||
await resendChatByUser(
|
||||
user.id,
|
||||
user.phone
|
||||
size="small"
|
||||
loading={user.loading}
|
||||
onClick={async (e) => {
|
||||
e.stopPropagation();
|
||||
const userId = parseInt(
|
||||
user.id
|
||||
);
|
||||
try {
|
||||
// Update user status to show loading
|
||||
const updatedUsers =
|
||||
notification.users.map(
|
||||
(u) =>
|
||||
u.notification_error_user_id ===
|
||||
userId
|
||||
? {
|
||||
...u,
|
||||
loading: true,
|
||||
}
|
||||
: u
|
||||
);
|
||||
setNotification({
|
||||
...notification,
|
||||
users: updatedUsers,
|
||||
});
|
||||
|
||||
// Call the resend API
|
||||
const response =
|
||||
await resendNotificationToUser(
|
||||
notification.notification_error_id,
|
||||
userId
|
||||
);
|
||||
|
||||
if (
|
||||
response &&
|
||||
response.statusCode ===
|
||||
200
|
||||
) {
|
||||
message.success(
|
||||
`Notification resent to ${user.name}`
|
||||
);
|
||||
|
||||
// Update user status
|
||||
const updatedUsersAfterSuccess =
|
||||
notification.users.map(
|
||||
(u) =>
|
||||
u.notification_error_user_id ===
|
||||
userId
|
||||
? {
|
||||
...u,
|
||||
is_send: true,
|
||||
status: 'sent',
|
||||
loading: false,
|
||||
}
|
||||
: {
|
||||
...u,
|
||||
loading: false,
|
||||
}
|
||||
);
|
||||
setNotification({
|
||||
...notification,
|
||||
users: updatedUsersAfterSuccess,
|
||||
});
|
||||
} else {
|
||||
throw new Error(
|
||||
response?.message ||
|
||||
'Failed to resend notification'
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
'Error resending notification:',
|
||||
error
|
||||
);
|
||||
message.error(
|
||||
error.message ||
|
||||
'Failed to resend notification'
|
||||
);
|
||||
|
||||
// Reset loading state
|
||||
const resetUsers =
|
||||
notification.users.map(
|
||||
(u) =>
|
||||
u.notification_error_user_id ===
|
||||
userId
|
||||
? {
|
||||
...u,
|
||||
loading: false,
|
||||
}
|
||||
: u
|
||||
);
|
||||
setNotification({
|
||||
...notification,
|
||||
users: resetUsers,
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
Resend
|
||||
</Button>
|
||||
</Col>
|
||||
</Space>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
@@ -542,25 +606,58 @@ const NotificationDetailTab = (props) => {
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row gutter={[8, 8]}>
|
||||
<Row gutter={[8, 8]} style={{ marginBottom: 'px' }}>
|
||||
<Col xs={24} md={8}>
|
||||
<div>
|
||||
<Card
|
||||
hoverable
|
||||
bodyStyle={{ padding: '12px'}}
|
||||
bodyStyle={{ padding: '12px', textAlign: 'center' }}
|
||||
>
|
||||
<Space>
|
||||
<BookOutlined
|
||||
style={{ fontSize: '16px', color: '#1890ff' }}
|
||||
/>
|
||||
<Text
|
||||
strong
|
||||
style={{ fontSize: '16px', color: '#262626' }}
|
||||
>
|
||||
<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"
|
||||
@@ -574,8 +671,7 @@ const NotificationDetailTab = (props) => {
|
||||
.map((sol, index) => (
|
||||
<div
|
||||
key={
|
||||
sol.brand_code_solution_id ||
|
||||
index
|
||||
sol.brand_code_solution_id || index
|
||||
}
|
||||
>
|
||||
{sol.path_document ? (
|
||||
@@ -590,8 +686,7 @@ const NotificationDetailTab = (props) => {
|
||||
<Text
|
||||
type="secondary"
|
||||
style={{
|
||||
fontSize:
|
||||
'10px',
|
||||
fontSize: '10px',
|
||||
}}
|
||||
>
|
||||
PDF
|
||||
@@ -603,8 +698,7 @@ const NotificationDetailTab = (props) => {
|
||||
display: 'flex',
|
||||
justifyContent:
|
||||
'space-between',
|
||||
alignItems:
|
||||
'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
@@ -647,11 +741,6 @@ const NotificationDetailTab = (props) => {
|
||||
sol.text_solution ? (
|
||||
<Card
|
||||
size="small"
|
||||
title={
|
||||
<Text strong>
|
||||
{sol.solution_name}:
|
||||
</Text>
|
||||
}
|
||||
bodyStyle={{
|
||||
padding: '8px 12px',
|
||||
marginBottom: '4px',
|
||||
@@ -660,8 +749,7 @@ const NotificationDetailTab = (props) => {
|
||||
<Text
|
||||
type="secondary"
|
||||
style={{
|
||||
fontSize:
|
||||
'10px',
|
||||
fontSize: '10px',
|
||||
}}
|
||||
>
|
||||
{sol.type_solution.toUpperCase()}
|
||||
@@ -669,10 +757,12 @@ const NotificationDetailTab = (props) => {
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<Text strong>
|
||||
{sol.solution_name}:
|
||||
</Text>
|
||||
<div
|
||||
style={{
|
||||
marginTop:
|
||||
'4px',
|
||||
marginTop: '4px',
|
||||
}}
|
||||
>
|
||||
{sol.text_solution}
|
||||
@@ -696,26 +786,13 @@ const NotificationDetailTab = (props) => {
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} md={8}>
|
||||
<div>
|
||||
<Card
|
||||
hoverable
|
||||
bodyStyle={{ padding: '12px'}}
|
||||
size="small"
|
||||
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
|
||||
direction="vertical"
|
||||
size="small"
|
||||
@@ -799,11 +876,9 @@ const NotificationDetailTab = (props) => {
|
||||
marginTop: '8px',
|
||||
}}
|
||||
>
|
||||
Kode:{' '}
|
||||
{sparepart.sparepart_code} |
|
||||
Qty:{' '}
|
||||
{sparepart.sparepart_qty} |
|
||||
Unit:{' '}
|
||||
Kode: {sparepart.sparepart_code}{' '}
|
||||
| Qty: {sparepart.sparepart_qty}{' '}
|
||||
| Unit:{' '}
|
||||
{sparepart.sparepart_unit}
|
||||
</div>
|
||||
</Space>
|
||||
@@ -824,23 +899,9 @@ const NotificationDetailTab = (props) => {
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} md={8}>
|
||||
<div>
|
||||
<Card bodyStyle={{ padding: '12px'}}>
|
||||
<Space>
|
||||
<HistoryOutlined
|
||||
style={{ fontSize: '16px', color: '#1890ff' }}
|
||||
/>
|
||||
<Text
|
||||
strong
|
||||
style={{ fontSize: '16px', color: '#262626' }}
|
||||
>
|
||||
Log Activity
|
||||
</Text>
|
||||
</Space>
|
||||
|
||||
<Card size="small" style={{ height: '100%' }}>
|
||||
<Space
|
||||
direction="vertical"
|
||||
size="small"
|
||||
@@ -850,9 +911,7 @@ const NotificationDetailTab = (props) => {
|
||||
size="small"
|
||||
bodyStyle={{
|
||||
padding: '8px 12px',
|
||||
backgroundColor: isAddingLog
|
||||
? '#fafafa'
|
||||
: '#fff',
|
||||
backgroundColor: isAddingLog ? '#fafafa' : '#fff',
|
||||
}}
|
||||
>
|
||||
<Space
|
||||
@@ -862,10 +921,7 @@ const NotificationDetailTab = (props) => {
|
||||
>
|
||||
{isAddingLog && (
|
||||
<>
|
||||
<Text
|
||||
strong
|
||||
style={{ fontSize: '12px' }}
|
||||
>
|
||||
<Text strong style={{ fontSize: '12px' }}>
|
||||
Add New Log / Update Progress
|
||||
</Text>
|
||||
<Input.TextArea
|
||||
@@ -873,9 +929,7 @@ const NotificationDetailTab = (props) => {
|
||||
placeholder="Tuliskan update penanganan di sini..."
|
||||
value={newLogDescription}
|
||||
onChange={(e) =>
|
||||
setNewLogDescription(
|
||||
e.target.value
|
||||
)
|
||||
setNewLogDescription(e.target.value)
|
||||
}
|
||||
disabled={submitLoading}
|
||||
/>
|
||||
@@ -927,22 +981,18 @@ const NotificationDetailTab = (props) => {
|
||||
>
|
||||
<Paragraph
|
||||
style={{ fontSize: '12px', margin: 0 }}
|
||||
// ellipsis={{ rows: 2 }}
|
||||
ellipsis={{ rows: 2 }}
|
||||
>
|
||||
<Text strong>{log.addedBy.name}:</Text>{' '}
|
||||
{log.description}
|
||||
</Paragraph>
|
||||
<Text
|
||||
type="secondary"
|
||||
style={{ fontSize: '11px' }}
|
||||
>
|
||||
<Text type="secondary" style={{ fontSize: '11px' }}>
|
||||
{log.timestamp}
|
||||
</Text>
|
||||
</Card>
|
||||
))}
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Space>
|
||||
|
||||
@@ -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;
|
||||