65 İşlemeler

Yazar SHA1 Mesaj Tarih
  Jason Chuang 467e9731fc Merge branch 'web_access_fix' into CR013B2 2 hafta önce
  Jason Chuang de4d310839 iAM Smart login fix 2 hafta önce
  Jason Chuang f270b5c83a forgot password, double click control 2 hafta önce
  Jason Chuang a6155bf36a iAM Smart handling 2 hafta önce
  Jason Chuang 40948a26f8 fix regsiterForm havent check email 2 hafta önce
  Jason Chuang 5a1d0f077a show messsage if iamsmart user already existing 2 hafta önce
  Jason Chuang 27c54c1bd7 user group validation 2 hafta önce
  Jason Chuang b33a9275b5 fix create user group 2 hafta önce
  Jason Chuang 3bd8bcc000 fix proof error 2 hafta önce
  Jason Chuang 70ea25cce2 fix MUI 2 hafta önce
  Jason Chuang 3da4bb5ae0 loading for export excel 2 hafta önce
  Jason Chuang 22232a6dab other double click button 2 hafta önce
  Jason Chuang 2b3fd67494 registration preview submit button control 2 hafta önce
  Jason Chuang 0904ddba63 fix district and email validation 2 hafta önce
  Jason Chuang b40345170d various changes 3 hafta önce
  Jason Chuang f86a80bfb2 fixed UI out of sync and multiple token expiry alert 3 hafta önce
  Jason Chuang 29f71088b2 update to new CSP with embed font 3 hafta önce
  Jason Chuang a1c8ef0b66 handle double verify link 3 hafta önce
  Jason Chuang fdb8163219 remove summary report 1000 days limit 3 hafta önce
  Jason Chuang 0db8ee2694 fix username and email validation check, used more than 0, then show error 3 hafta önce
  Jason Chuang 35259e9cdd fix audit log search and export criteria bug 3 hafta önce
  Jason Chuang 6c69e10164 fix gld user blank page 3 hafta önce
  Jason Chuang a783b7a895 fix double click on login button 3 hafta önce
  Jason Chuang 15d9736fcf avoid double click to org page 3 hafta önce
  Jason Chuang b6415f1be9 avoid double click issue for public update user record 3 hafta önce
  Jason Chuang 2e4c44629f improve forgot password page 3 hafta önce
  Jason Chuang 40dd3d56ec avoid double click from changing password form 3 hafta önce
  Jason Chuang f009bb8138 handle double verify email 3 hafta önce
  Jason Chuang 0ff322d87a avoid double click to forgot page 1 ay önce
  Jason Chuang d6ec014a26 add back toastify message box with 30 sec 1 ay önce
  Jason Chuang cbe3357883 incident update 1 ay önce
  Jason Chuang 71339bd540 update to avoid displaying too much alert "Login verification has expired, please log in again." 1 ay önce
  Jason Chuang 7673697565 apply html title and description to match the page contents 1 ay önce
  Jason Chuang c9b48778ed button add keyboard control 1 ay önce
  Jason Chuang 3e4f5227b6 button add keyboard control 1 ay önce
  Jason Chuang ea5529d24b remove toastify and change to dialog box 1 ay önce
  Jason Chuang 42a8501fd2 fix for concurrent create proof an check create 1 ay önce
  Jason Chuang 1f16b40fe9 aria-label for careOf 2 ay önce
  Jason Chuang b648db4023 added back missing i18n 2 ay önce
  Jason Chuang 20accadbe1 add back aria-label with i18n 2 ay önce
  Jason Chuang 23918f7cf1 update all aria-label 2 ay önce
  Jason Chuang 572762b31c add i18n 2 ay önce
  Jason Chuang 1a85f8f146 update navbar style 2 ay önce
  Jason Chuang 5aa7d51974 minor adjust login page layout 2 ay önce
  Jason Chuang d5dc361b87 avoid displaying too much alert "Login verification has expired, please log in again." 2 ay önce
  Jason Chuang dbb1462474 avoid double click to submit in application form 2 ay önce
  Jason Chuang 6de845a965 CR020 - remove importantNotice and landingMessage and privacyPolicy to settings 2 ay önce
  Jason Chuang f6c68b0327 CR020 - remove importantNotice and landingMessage and privacyPolicy to settings 2 ay önce
  Jason Chuang 1e8e9402d1 fix multiple reply proof and reset username and password 2 ay önce
  Jason Chuang 933bfe2752 update reset button in FormWizard 2 ay önce
  Jason Chuang 9a0e515d64 update style. 2 ay önce
  Jason Chuang 4978621d6b double the message display time 2 ay önce
  Jason Chuang a865e4e3f3 WCAG 2.0 A 1.3.1 Info and Relationships 2 ay önce
  Jason Chuang 8bc293c817 Merge branch 'web_access_fix' of https://git.2fi-solutions.com/alex/PNSPS-frontend-MaterialUI into web_access_fix 2 ay önce
  Jason Chuang bc87f5df36 Async Queue for Fallback Excel with Email 2 ay önce
  Alex Cheung e7d1c3402e update WCAG to 4.1.2 2 ay önce
  Alex Cheung 617904b649 WCAG 1.3.1 and add back 1.1.1 2 ay önce
  Jason Chuang 1a74f172d9 WCAG 2.0, A 4.1.2 Name, Role, Value 2 ay önce
  Jason Chuang a412582bbc remove border 2 ay önce
  Jason Chuang 686ca8aeeb WCAG 2.0 AA 1.4.3 Contrast (Minimum) 2 ay önce
  Jason Chuang 3e7280485f add back footer info 2 ay önce
  Jason Chuang 27b5128b23 WCAG 2.0, AA 2.4.7 Focus Visible 2 ay önce
  Jason Chuang bfecc333d6 WCAG 2.1, AA 1.4.11 Non-Text Contrast 2 ay önce
  Alex Cheung f3f75f97c6 add audio for captcha 2 ay önce
  Alex Cheung e8690f0baf update 1.1.1 and test audio in window 2 ay önce
100 değiştirilmiş dosya ile 15616 ekleme ve 7873 silme
  1. +51
    -0
      docs/csp-apache.conf.md
  2. +12770
    -6394
      package-lock.json
  3. +3
    -0
      package.json
  4. +3
    -8
      public/index.html
  5. +11
    -12
      src/App.js
  6. +19
    -0
      src/assets/fonts.css
  7. +330
    -114
      src/assets/style/navbarStyles.css
  8. +88
    -20
      src/assets/style/styles.css
  9. +41
    -9
      src/auth/index.js
  10. +3
    -0
      src/auth/utils.js
  11. +1
    -5
      src/components/@extended/AnimateButton.js
  12. +23
    -11
      src/components/AdminLogo/index.js
  13. +11
    -3
      src/components/AutoLogoutProvider.js
  14. +62
    -12
      src/components/FiDataGrid.js
  15. +4
    -0
      src/components/Logo/index.js
  16. +27
    -1
      src/components/MainCard.js
  17. +21
    -8
      src/components/MobileLogo/index.js
  18. +33
    -16
      src/components/cards/AuthFooter.js
  19. +3
    -2
      src/components/iAmSmartButton.js
  20. +42
    -0
      src/components/usePageTitle.js
  21. +2
    -1
      src/index.js
  22. +3
    -1
      src/layout/MainLayout/Drawer/index.js
  23. +22
    -10
      src/layout/MainLayout/Header/HeaderContent/LocaleSelector.js
  24. +20
    -13
      src/layout/MainLayout/Header/HeaderContent/MobileSection.js
  25. +16
    -6
      src/layout/MainLayout/Header/HeaderContent/Notification.js
  26. +4
    -2
      src/layout/MainLayout/Header/HeaderContent/Profile/index.js
  27. +824
    -745
      src/layout/MainLayout/Header/index.js
  28. +1
    -1
      src/layout/MainLayout/index.js
  29. +3
    -3
      src/pages/Announcement/Details/AnnouncementForm.js
  30. +4
    -2
      src/pages/Announcement/Search_Public/SearchForm.js
  31. +3
    -2
      src/pages/Announcement/Search_Public/index.js
  32. +16
    -11
      src/pages/AuditLog/AuditLogSearchForm.js
  33. +11
    -4
      src/pages/DemandNote/Create/SearchForm.js
  34. +7
    -3
      src/pages/DemandNote/Details/ApplicationDetailCard.js
  35. +6
    -4
      src/pages/DemandNote/Details/DnDetailCard.js
  36. +5
    -1
      src/pages/DemandNote/Export/SearchForm.js
  37. +11
    -8
      src/pages/DemandNote/Search/DataGrid.js
  38. +13
    -1
      src/pages/DemandNote/Search/SearchForm.js
  39. +1
    -2
      src/pages/DemandNote/Search_Public/DataGrid.js
  40. +11
    -5
      src/pages/DemandNote/Search_Public/SearchForm.js
  41. +3
    -2
      src/pages/DemandNote/Search_Public/index.js
  42. +2
    -4
      src/pages/GFMIS/SearchForm.js
  43. +53
    -30
      src/pages/GFMIS/index.js
  44. +5
    -1
      src/pages/GazetteIssue/ExportForm.js
  45. +5
    -1
      src/pages/GazetteIssue/SearchForm.js
  46. +22
    -5
      src/pages/GazetteIssue/index.js
  47. +8
    -3
      src/pages/Holiday/DataGrid.js
  48. +9
    -5
      src/pages/Holiday/SearchForm.js
  49. +23
    -7
      src/pages/Holiday/index.js
  50. +82
    -16
      src/pages/JVM/index.js
  51. +7
    -3
      src/pages/Message/Details/index.js
  52. +2
    -2
      src/pages/Message/Search/SearchForm.js
  53. +3
    -2
      src/pages/Message/Search/index.js
  54. +57
    -51
      src/pages/Organization/DetailPage/OrganizationCard.js
  55. +42
    -34
      src/pages/Organization/DetailPage/OrganizationPubCard.js
  56. +6
    -2
      src/pages/Organization/DetailPage/index.js
  57. +1
    -1
      src/pages/Organization/DetailPage_FromUser/OrganizationCard_loadFromUser.js
  58. +4
    -0
      src/pages/Organization/DetailPage_FromUser/index.js
  59. +1
    -1
      src/pages/Organization/SearchPage/OrganizationSearchForm.js
  60. +3
    -0
      src/pages/Organization/SearchPage/index.js
  61. +5
    -2
      src/pages/Payment/Details_Public/index.js
  62. +4
    -8
      src/pages/Payment/Search_GLD/SearchForm.js
  63. +9
    -6
      src/pages/Payment/Search_Public/SearchForm.js
  64. +3
    -1
      src/pages/Payment/Search_Public/index.js
  65. +49
    -12
      src/pages/Proof/Create_FromApp/ProofForm.js
  66. +3
    -3
      src/pages/Proof/Create_FromApp/index.js
  67. +52
    -8
      src/pages/Proof/Reply_GLD/ApplicationDetails.js
  68. +36
    -18
      src/pages/Proof/Reply_Public/ProofForm.js
  69. +7
    -9
      src/pages/Proof/Reply_Public/index.js
  70. +5
    -1
      src/pages/Proof/Search_GLD/DataGrid.js
  71. +15
    -16
      src/pages/Proof/Search_GLD/SearchForm.js
  72. +12
    -1
      src/pages/Proof/Search_Public/DataGrid.js
  73. +19
    -9
      src/pages/Proof/Search_Public/SearchForm.js
  74. +4
    -2
      src/pages/Proof/Search_Public/index.js
  75. +6
    -5
      src/pages/PublicNotice/ApplyForm/PublicNoticeApplyForm.js
  76. +5
    -3
      src/pages/PublicNotice/ApplyForm/index.js
  77. +76
    -40
      src/pages/PublicNotice/Details_GLD/ApplicationDetailCard.js
  78. +14
    -5
      src/pages/PublicNotice/Details_GLD/GazetteDetailCard.js
  79. +61
    -21
      src/pages/PublicNotice/Details_GLD/StatusChangeDialog.js
  80. +115
    -21
      src/pages/PublicNotice/Details_GLD/index.js
  81. +8
    -0
      src/pages/PublicNotice/Details_GLD/tabTableDetail/PaymentTab.js
  82. +11
    -2
      src/pages/PublicNotice/Details_GLD/tabTableDetail/ProofTab.js
  83. +8
    -1
      src/pages/PublicNotice/Details_GLD/tabTableDetail/StatusHistoryTab.js
  84. +6
    -5
      src/pages/PublicNotice/Details_GLD/tabTableDetail/TabTable.js
  85. +14
    -4
      src/pages/PublicNotice/Details_Public/ApplicationDetailCard.js
  86. +33
    -10
      src/pages/PublicNotice/Details_Public/StatusChangeDialog.js
  87. +22
    -4
      src/pages/PublicNotice/Details_Public/index.js
  88. +8
    -0
      src/pages/PublicNotice/Details_Public/tabTableDetail/PaymentTab.js
  89. +10
    -3
      src/pages/PublicNotice/Details_Public/tabTableDetail/ProofTab.js
  90. +10
    -2
      src/pages/PublicNotice/Details_Public/tabTableDetail/StatusHistoryTab.js
  91. +1
    -1
      src/pages/PublicNotice/Details_Public/tabTableDetail/TabTable.js
  92. +10
    -2
      src/pages/PublicNotice/ListPanel/BaseGrid.js
  93. +40
    -17
      src/pages/PublicNotice/ListPanel/PendingPaymentTab.js
  94. +16
    -4
      src/pages/PublicNotice/ListPanel/SearchPublicNoticeForm.js
  95. +11
    -2
      src/pages/PublicNotice/ListPanel/SearchPublicNoticeTable.js
  96. +11
    -6
      src/pages/PublicNotice/ListPanel/index.js
  97. +14
    -3
      src/pages/PublicNotice/Search_GLD/DataGrid.js
  98. +4
    -4
      src/pages/PublicNotice/Search_GLD/SearchForm.js
  99. +10
    -0
      src/pages/PublicNotice/Search_Mark_As_Paid_GLD/DataGrid.js
  100. +2
    -2
      src/pages/PublicNotice/Search_Mark_As_Paid_GLD/SearchForm.js

+ 51
- 0
docs/csp-apache.conf.md Dosyayı Görüntüle

@@ -0,0 +1,51 @@
# Content-Security-Policy (Apache)

Self-hosted fonts: no `fonts.googleapis.com` or `fonts.gstatic.com`. Static assets (including `woff2`) are served from `'self'`.

Adjust `report-uri` if your API base path or host differs (example below targets UAT).

## Enforcing

```apache
Header always set Content-Security-Policy "default-src 'self'; \
base-uri 'self'; \
object-src 'none'; \
frame-ancestors 'none'; \
form-action 'self'; \
script-src 'self'; \
style-src 'self' 'unsafe-inline'; \
style-src-elem 'self' 'unsafe-inline'; \
img-src 'self' data: https://www.w3.org https://w3.org; \
media-src 'self' blob:; \
font-src 'self' data:; \
connect-src 'self'; \
upgrade-insecure-requests"
```

## Report-Only

Same policy plus violation reporting:

```apache
Header always set Content-Security-Policy-Report-Only "default-src 'self'; \
base-uri 'self'; \
object-src 'none'; \
frame-ancestors 'none'; \
form-action 'self'; \
script-src 'self'; \
style-src 'self' 'unsafe-inline'; \
style-src-elem 'self' 'unsafe-inline'; \
img-src 'self' data: https://www.w3.org https://w3.org; \
media-src 'self' blob:; \
font-src 'self' data:; \
connect-src 'self'; \
upgrade-insecure-requests; \
report-uri https://pnspsuat.gld.gov.hk/api/csp-report"
```

## Notes

- **`style-src-elem`**: Explicit, alongside `style-src`, for `<link rel="stylesheet">` behaviour in modern browsers.
- **`img-src`**: Includes `https://www.w3.org` and `https://w3.org` so W3C URLs that redirect between hosts are allowed.
- **`font-src`**: `'self' data:` covers bundled fonts and `data:` URLs if used.
- Add origins to the relevant directive only if you introduce third-party scripts, styles, fonts, or APIs.

+ 12770
- 6394
package-lock.json
Dosya farkı çok büyük olduğundan ihmal edildi
Dosyayı Görüntüle


+ 3
- 0
package.json Dosyayı Görüntüle

@@ -10,6 +10,9 @@
"@emotion/cache": "^11.10.3",
"@emotion/react": "^11.10.4",
"@emotion/styled": "^11.10.4",
"@fontsource/noto-sans-hk": "^5.2.9",
"@fontsource/noto-sans-sc": "^5.2.9",
"@fontsource/public-sans": "^5.2.7",
"@material-ui/pickers": "^3.3.10",
"@mui/icons-material": "^5.14.1",
"@mui/lab": "^5.0.0-alpha.139",


+ 3
- 8
public/index.html Dosyayı Görüntüle

@@ -8,10 +8,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#ffffff" />
<meta name="msapplication-TileColor" content="#da532c">
<meta name="title" content="PNSPS" />
<meta name="title" content="PNSPS - Public Notice Submission and Payment System" />
<meta
name="description"
content="The Government of the Hong Kong Special Administrative Region Gazette Public Notice Submission and Payment System."
content="Public Notice Submission and Payment System - Government Logistics Department"
/>
<meta
name="keywords"
@@ -19,12 +19,7 @@
/>
<meta name="author" content="Government Logistics Department" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/apple-touch-icon.png" />
<title>PNSPS</title>
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap&family=Public+Sans:wght@400;500;600;700"
rel="stylesheet"
/>
<title>PNSPS - Public Notice Submission and Payment System</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>


+ 11
- 12
src/App.js Dosyayı Görüntüle

@@ -2,24 +2,23 @@
import Routes from 'routes';
import ThemeCustomization from 'themes';
import ScrollTop from 'components/ScrollTop';
import {ToastContainer} from "react-toastify";
import { PNSPS_THEME } from './themes/themeConst';
import { ThemeProvider } from '@emotion/react';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import {PNSPS_THEME} from "./themes/themeConst";
import {ThemeProvider} from "@emotion/react";
//import {isUserLoggedIn} from 'utils/Utils';
//import {DefaultRoute} from 'routes/index'
// ==============================|| APP - THEME, ROUTER, LOCAL ||============================== //

const App = () => (
<ThemeCustomization>
<ThemeProvider theme={PNSPS_THEME}>
<ScrollTop>
<Routes>
</Routes>
</ScrollTop>
</ThemeProvider>
<ToastContainer/>
</ThemeCustomization>
<ThemeCustomization>
<ThemeProvider theme={PNSPS_THEME}>
<ScrollTop>
<Routes />
</ScrollTop>
</ThemeProvider>
<ToastContainer />
</ThemeCustomization>
);

export default App;

+ 19
- 0
src/assets/fonts.css Dosyayı Görüntüle

@@ -0,0 +1,19 @@
/* Self-hosted fonts (bundled via @fontsource; no Google Fonts CDN — CSP-friendly). */

/* Public Sans — MUI theme (`themeConst.js`), charts, config */
@import "@fontsource/public-sans/400.css";
@import "@fontsource/public-sans/500.css";
@import "@fontsource/public-sans/600.css";
@import "@fontsource/public-sans/700.css";

/* Noto Sans HK — `styles.css` / navbar (Latin + Hong Kong glyphs) */
@import "@fontsource/noto-sans-hk/latin-400.css";
@import "@fontsource/noto-sans-hk/chinese-hongkong-400.css";
@import "@fontsource/noto-sans-hk/latin-600.css";
@import "@fontsource/noto-sans-hk/chinese-hongkong-600.css";

/* Noto Sans SC — fallback for simplified Chinese */
@import "@fontsource/noto-sans-sc/latin-400.css";
@import "@fontsource/noto-sans-sc/chinese-simplified-400.css";
@import "@fontsource/noto-sans-sc/latin-600.css";
@import "@fontsource/noto-sans-sc/chinese-simplified-600.css";

+ 330
- 114
src/assets/style/navbarStyles.css Dosyayı Görüntüle

@@ -1,162 +1,378 @@
/* assets/style/navbarStyles.css */

/* ===== FIX typo ===== */
#nav{
display: flex;
align-items: center;
justify-content: space-between;
background-color: white;
/* padding: 20px 80px; */
box-shadow: 0 5px 15px rgba(0,0 0,0,0.06);
position:fixed;
top: 0px;
width: 100%;
z-index: 9999;
border-bottom: 3px solid #0C489E;
display: flex;
align-items: center;
justify-content: space-between;
background-color: white;
box-shadow: 0 5px 15px rgba(0,0,0,0.06); /* <-- fixed */
position: fixed;
top: 0px;
width: 100%;
z-index: 9999;
border-bottom: 3px solid #0C489E;
min-height: 77px;
}

#navbar > div > li {
height: 77px; /* one single source of truth */
display: flex;
align-items: stretch;
padding: 0; /* IMPORTANT: stop li padding making different widths */
margin: 0;
}

#navbar div li{
padding: 0; /* override your earlier padding: 0 1vw */
}

/* Make dropdown button identical to anchor */
#navbar > div > li > button.navTrigger {
background: transparent;
border: 0;
padding: 0; /* remove default button padding */
margin: 0;
font: inherit; /* inherit font from li */
line-height: 1; /* normalize */
height: auto;
display: inline-flex;
align-items: center;
cursor: pointer;
}

/* Make both anchor and button same vertical box */
#navbar > div > li > a,
#navbar > div > li > button.navTrigger {
height: 100% !important; /* override the old 72px */
padding: 0 24px !important; /* bigger hit area */
display: flex;
align-items: center;
box-sizing: border-box;
}

/* Submenu triggers: same font as app (Noto Sans), bold */
#navbar > div > li > button.navTrigger,
#navbar > div > li > button.navTrigger .MuiTypography-root {
font-weight: 600 !important;
font-family: "Noto Sans HK", "Noto Sans SC", sans-serif !important;
font-size: 1.1rem !important;
}

/* Keep links bold */
#navbar > div > li > a,
#navbar > div > li > a .MuiTypography-root {
font-weight: 600;
}

#navbar div{
display: flex;
align-items: center;
justify-content: center;
display: flex;
align-items: center;
justify-content: center;
}

#navbar div li{
list-style: none;
padding: 0 1vw;
position: relative;
list-style: none;
padding: 0 1vw;
position: relative;
}

/* keep your <a> styling */
#navbar div li a{
text-decoration: none;
font-size: 1.2rem;
font-weight: 600;
/* font-family: 微軟正黑體; */
color: black;
transition: 0.3s ease-in-out;
text-decoration: none;
font-size: 1.2rem;
font-weight: 600;
color: black;
transition: 0.3s ease-in-out;
}

#navbar div li a span{
font-size: 1vw !important;
/* Dropdown trigger buttons: Noto Sans, bold */
#navbar div li button.navTrigger{
background: transparent;
border: 0;
padding: 0;
cursor: pointer;

text-decoration: none;
font-size: 1.1rem;
font-weight: 600;
font-family: "Noto Sans HK", "Noto Sans SC", sans-serif;
color: black;
transition: 0.3s ease-in-out;

display: inline-flex;
align-items: center;
gap: 0.25rem;
}

#navbar div li a span,
#navbar div li a svg{
font-size: 1vw !important;
font-size: 1vw !important;
}

#navbar div li a:hover{
color: #0C489E;
#navbar div li a:hover,
#navbar div li button.navTrigger:hover{
color: #0C489E;
}

#navbar div li a:hover::after,
#navbar div li a:focus::after{
content: "";
width: 80%;
height: 3px;
background:#0C489E;
position: absolute;
bottom: -5px;
left: 20px;
}
#navbar div li ul {
#navbar div li a:focus-visible::after,
#navbar div li button.navTrigger:hover::after,
#navbar div li button.navTrigger:focus-visible::after{
content: "";
width: 80%;
height: 3px;
background:#0C489E;
position: absolute;
bottom: -5px;
left: 20px;
}

/* submenu base */
#navbar div li ul{
background: white;
visibility: hidden;
opacity: 0;
min-width: 18rem;
position: absolute;
/* transition: all 0.5s ease; */
left: 0;
display: none;
padding-left: 0px;
padding-bottom: 7px;
/* border: 1px solid #0C489E; */
background-clip: padding-box;
border: 1px solid rgba(0,0,0,.15);
border-radius: 0.25rem;
}
#navbar div li:hover > ul{
visibility: visible;
opacity: 1;
display: block
}
/* #navbar div li:focus-within > ul,
#navbar div li ul:hover,
#navbar div li ul:focus {

/* hover open */
#navbar div li:hover > ul{
visibility: visible;
opacity: 1;
display: block;
}

/* keyboard open */
#navbar div li:focus-within > ul{
visibility: visible;
opacity: 1;
display: block
} */
display: block;
}

/* Navbar focus ring */
#navbar a:focus,
#navbar button.navTrigger:focus{
outline: none;
}

#navbar a:focus-visible,
#navbar button.navTrigger:focus-visible{
outline: 3px solid #0C489E;
outline-offset: 2px;
border-radius: 10px;
}

/* Top-level links (Dashboard, Application, Proof, Logout, etc.) */
#navbar a.dashboard,
#navbar a.application,
#navbar a.proof,
#navbar a.myDocumet,
#navbar a.documentRecord,
#navbar a.manageOrgUser,
#navbar a.manageUser,
#navbar a.systemSetting,
#navbar a.report,
#navbar a.payment,
#navbar a.user,
#navbar a.logout {
font-size: 1.1rem !important;
font-weight: 600 !important;
}

#navbar a.dashboard .MuiTypography-root,
#navbar a.application .MuiTypography-root,
#navbar a.proof .MuiTypography-root,
#navbar a.myDocumet .MuiTypography-root,
#navbar a.documentRecord .MuiTypography-root,
#navbar a.manageOrgUser .MuiTypography-root,
#navbar a.manageUser .MuiTypography-root,
#navbar a.systemSetting .MuiTypography-root,
#navbar a.report .MuiTypography-root,
#navbar a.payment .MuiTypography-root,
#navbar a.user .MuiTypography-root,
#navbar a.logout .MuiTypography-root {
font-size: 1.1rem !important;
font-weight: 600 !important;
}

/* Submenu triggers: Noto Sans, 1.1rem, bold */
#navbar button.navTrigger.paymentTop,
#navbar button.navTrigger.client,
#navbar button.navTrigger.setting,
#navbar button.navTrigger.paymentRecord,
#navbar button.navTrigger.userSetting,
#navbar button.navTrigger.paymentTop .MuiTypography-root,
#navbar button.navTrigger.client .MuiTypography-root,
#navbar button.navTrigger.setting .MuiTypography-root,
#navbar button.navTrigger.paymentRecord .MuiTypography-root,
#navbar button.navTrigger.userSetting .MuiTypography-root {
font-size: 1.1rem !important;
font-weight: 600 !important;
font-family: "Noto Sans HK", "Noto Sans SC", sans-serif !important;
}

/* Make them bigger + bold */
#navbar a.login,
#navbar a.register,
#navbar a.login .MuiTypography-root,
#navbar a.register .MuiTypography-root {
font-size: 1.1rem !important;
font-weight: 600 !important;
}

/* ===== your existing sidebar (unchanged) ===== */
#systemTitle{
text-decoration: none;
font-size: 1.3rem;
font-weight: 600;
color: #0C489E;
transition: 0.3s ease-in-out;
/* font-family: 微軟正黑體; */
text-align: center;
text-decoration: none;
font-size: 1.1rem;
font-weight: 600;
color: #0C489E;
transition: 0.3s ease-in-out;
text-align: center;
}
#mobileTitle{
text-decoration: none;
font-size: 1.2rem;
font-weight: 600;
color: #0C489E;
transition: 0.3s ease-in-out;
/* font-family: 微軟正黑體; */
text-align: center;
text-decoration: none;
font-size: 1.1rem;
font-weight: 600;
color: #0C489E;
transition: 0.3s ease-in-out;
text-align: center;
}
#sidebar{
font-size: 1.3rem;
font-weight: 600;
/* font-family: 微軟正黑體; */
font-size: 1.1rem;
font-weight: 600;
}
#sidebartop{
align-items: center;
justify-content: start;
padding: 0;
display: flex;
width: 100%;
align-items: center;
justify-content: start;
padding: 0;
display: flex;
width: 100%;
}
#logoutContent{
align-items: center;
justify-content: center;
padding: 0;
display: flex;
width: 100%;
align-items: center;
justify-content: center;
padding: 0;
display: flex;
width: 100%;
}
#sidebarbottom{
align-items: center;
justify-content: center;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
display: flex;
}
#sidebar li{
list-style: none;
padding: 0 20px;
position: relative;
text-align: left;
list-style: none;
padding: 0 20px;
position: relative;
text-align: left;
}
#sidebar li a{
text-decoration: none;
font-size: 1.3rem;
font-weight: 600;
/* font-family: 微軟正黑體; */
color: black;
transition: 0.3s ease-in-out;
text-decoration: none;
font-size: 1.1rem;
font-weight: 600;
color: black;
transition: 0.3s ease-in-out;
}
#sidebar li a:hover{
color: #0C489E;
}
#sidebar div li ul {
background: white;
visibility: hidden;
opacity: 0;
min-width: 16rem;
position: relative;
/* transition: all 0.5s ease; */
left: 0;
display: none;
padding-left: 0px;
/* border: 1px solid #0C489E; */
}
#sidebar div li:hover > ul,
#sidebar div li:focus-within > ul,
#sidebar div li ul:hover,
#sidebar div li ul:focus {
visibility: visible;
opacity: 1;
display: block
}
color: #0C489E;
}
#sidebar div li ul{
background: white;
visibility: hidden;
opacity: 0;
min-width: 16rem;
position: relative;
left: 0;
display: none;
padding-left: 0px;
}
#sidebar div li:hover > ul,
#sidebar div li:focus-within > ul,
#sidebar div li ul:hover,
#sidebar div li ul:focus{
visibility: visible;
opacity: 1;
display: block;
}

/* ===== Mobile Drawer / Sidebar menu styling ===== */
#sidebar ul {
width: 100%;
padding: 0;
margin: 0;
}

#sidebar li{
width: 100%;
padding: 0; /* remove the old 0 20px */
margin: 0;
}

/* Make BOTH links and dropdown buttons look the same */
#sidebar li > a,
#sidebar li > button.navTrigger{
width: 100%;
display: flex;
align-items: center;
justify-content: space-between; /* text left, arrow right */
gap: 12px;

background: transparent;
border: 0; /* kill grey border */
box-shadow: none;
outline: none;

padding: 14px 20px;
text-align: left;

font-size: 1.3rem;
font-weight: 600;
color: black;
cursor: pointer;
}

/* Hover / focus */
#sidebar li > a:hover,
#sidebar li > button.navTrigger:hover{
color: #0C489E;
}

#sidebar li > a:focus-visible,
#sidebar li > button.navTrigger:focus-visible{
outline: 3px solid #0C489E;
outline-offset: 2px;
border-radius: 10px;
}

/* Submenu (indent + full width) */
#sidebar li ul{
width: 100%;
padding: 6px 0 6px 0;
margin: 0;
display: none;
visibility: hidden;
opacity: 0;
}

/* Open on focus-within (tap/click focuses button) */
#sidebar li:focus-within > ul{
display: block;
visibility: visible;
opacity: 1;
}

#sidebar li ul li > a{
padding: 12px 20px 12px 40px; /* indent submenu */
font-size: 1.15rem;
font-weight: 600;
}

+ 88
- 20
src/assets/style/styles.css Dosyayı Görüntüle

@@ -1,6 +1,3 @@
@import url('https://fonts.googleapis.com/css?family=Noto+Sans+HK|Noto+Sans+SC&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC&display=swap');

html,
body,
#root,
@@ -52,26 +49,97 @@ img

img:hover{-webkit-filter:none;}


a:link {
color: #1890ff;
a:link,
a:visited,
a:hover,
a:active {
color: #005FCC; /* WCAG AA compliant */
background-color: transparent;
text-decoration: none;
text-decoration: underline;
}
a:visited {
color: #1890ff;
background-color: transparent;
text-decoration: none;

/* iframe#webpack-dev-server-client-overlay{display:none!important} */

/* ===== WCAG 2.4.7 Focus Visible (Keyboard only) ===== */
:where(
a,
button,
input,
select,
textarea,
summary,
[role="button"],
[role="link"],
[tabindex]:not([tabindex="-1"])
):focus-visible {
outline: 3px solid #0C489E;
outline-offset: 2px;
border-radius: 4px;
}
a:hover {
color: #1890ff;
background-color: transparent;
text-decoration: none;

/* Suppress mouse focus */
:where(
a,
button,
input,
select,
textarea,
summary,
[role="button"],
[role="link"],
[tabindex]:not([tabindex="-1"])
):focus:not(:focus-visible) {
outline: none;
}
a:active {
color: #1890ff;
background-color: transparent;
text-decoration: none;

/* ===== MUI DataGrid keyboard focus (WCAG 2.4.7 / 2.4.11) ===== */
.MuiDataGrid-columnHeader:focus-visible,
.MuiDataGrid-cell:focus-visible {
outline: 3px solid #0C489E;
outline-offset: -2px;
box-shadow: 0 0 0 3px rgba(12, 72, 158, 0.25);
}

/* Contained buttons only */
.MuiButton-contained {
box-shadow: none;
}

.MuiButton-contained:hover {
}

/* iAM Smart button — keep green border */
.MuiButton-outlinedIAmSmart {
color: #2E7D32; /* green text */
border: 1px solid #2E7D32; /* keep your green */
}

.MuiButton-outlinedIAmSmart:hover {
color: #2E7D32; /* green text */
border: 1px solid #2E7D32;
background-color: rgba(46, 125, 50, 0.08); /* optional */
}

/* ===== Outlined button focus ===== */
.MuiButton-outlined:focus-visible {
outline: 3px solid #0C489E;
outline-offset: 2px;
}

/* Step icon number color (text inside the circle) */
.MuiStepIcon-text {
fill: #1A1A1A; /* dark text, high contrast */
}
/* Placeholder text contrast */
.MuiInputBase-input::placeholder {
color: #6B6B6B; /* passes 4.5:1 on white */
opacity: 1; /* IMPORTANT */
}

/* iframe#webpack-dev-server-client-overlay{display:none!important} */
/* WCAG-safe error text color */
.Mui-error,
.MuiFormHelperText-root.Mui-error,
.MuiTypography-errorMessage1 {
color: #B00020; /* dark red, AA compliant */
opacity: 1; /* remove faded appearance */
}

+ 41
- 9
src/auth/index.js Dosyayı Görüntüle

@@ -13,6 +13,12 @@ export const windowCount = 'windowCount'
import {useNavigate} from "react-router-dom";
import {useDispatch} from "react-redux";
import { REFRESH_TOKEN } from 'utils/ApiPathConst';
import { getMessage } from 'utils/getI18nMessage';

// Guard so we only register interceptors once (ThemeRoutes re-renders add duplicate handlers otherwise)
let axiosInterceptorsSetup = false;
// In-memory guard so only one 401/logout flow shows the alert (avoids race when multiple 401s or interceptors run)
let expiredAlertShownInMemory = false;

// ** Handle User Login
export const handleLogin = data => {
@@ -39,6 +45,8 @@ export const handleLogin = data => {
localStorage.setItem(windowCount, '0')
localStorage.setItem(predictProductionQty, '0')
localStorage.setItem(predictUsageCount, '0')
localStorage.removeItem('expiredAlertShown')
expiredAlertShownInMemory = false
}
}

@@ -94,7 +102,9 @@ export const handleLogoutFunction = () => {
localStorage.removeItem('transactionid')
localStorage.removeItem('searchCriteria')
//localStorage.removeItem(config.storageUserRoleKeyName)
localStorage.removeItem('expiredAlertShown')
// Do not clear expiredAlertShown / expiredAlertShownInMemory here: logout runs right after
// the token-expired alert, and parallel 401s would each show another popup if we reset.
// Reset those only on successful login (handleLogin).
localStorage.removeItem(refreshIntervalName)
localStorage.removeItem(windowCount)
localStorage.removeItem(predictProductionQty)
@@ -109,7 +119,13 @@ export const SetupAxiosInterceptors = () => {
const dispatch = useDispatch();
//const updateLastRequestTime = useContext(TimerContext);
let isRefreshToken= false;

// Avoid stacking interceptors on every ThemeRoutes re-render (would cause multiple alerts on 401)
if (axiosInterceptorsSetup) {
return;
}
axiosInterceptorsSetup = true;

axios.interceptors.request.use(
config => {
// ** Get token from localStorage
@@ -134,7 +150,17 @@ export const SetupAxiosInterceptors = () => {
},
async (error) => {
// const { config, response: { status } } = error
if (error.response.status === 401 && error.config.url !== apiPath + REFRESH_TOKEN) {
const status = error.response?.status
const reqUrl = error.config?.url || ''
// iAM Smart registration: HKID already linked — caller must show /iamsmart/pleaseLogin (not refresh/logout)
if (
status === 401 &&
reqUrl.includes('/smart/getProfile') &&
error.response?.data?.exception === 'msg: account created'
) {
return Promise.reject(error)
}
if (status === 401 && error.config?.url !== apiPath + REFRESH_TOKEN) {
// Make a request to refresh the access token
const refreshToken = localStorage.getItem('refreshToken');
if (isRefreshToken) {
@@ -156,17 +182,23 @@ export const SetupAxiosInterceptors = () => {
}
})
.catch((refreshError) => {
isRefreshToken = false;
if (!expiredAlertShownInMemory && localStorage.getItem("expiredAlertShown") === null) {
expiredAlertShownInMemory = true;
localStorage.setItem("expiredAlertShown", "true");
alert(getMessage("autoLogout"));
}
dispatch(handleLogoutFunction());
navigate('/login');
isRefreshToken = false;
window.location.reload();
throw refreshError;
});
} else {
if (error.response.status === 401) {
if (localStorage.getItem("expiredAlertShown") === null) {
localStorage.setItem("expiredAlertShown", true)
alert("登入驗證已過期,請重新登入。")
if (error.response && error.response.status === 401) {
if (!expiredAlertShownInMemory && localStorage.getItem("expiredAlertShown") === null) {
expiredAlertShownInMemory = true;
localStorage.setItem("expiredAlertShown", "true");
alert(getMessage("autoLogout"));
}
}
@@ -191,7 +223,7 @@ export const SetupAxiosInterceptors = () => {
await window.location.reload();
}

if (error.response.status === 500){
if (error.response?.status === 500){
//setIsUploading(false);
}
// console.log(error)


+ 3
- 0
src/auth/utils.js Dosyayı Görüntüle

@@ -171,3 +171,6 @@ export const getPaymentMethodByCode = (code) => {
return "other";
};

export function setPageTitle(title) {
document.title = `${title} - PNSPS | Government Logistics Department`;
}

+ 1
- 5
src/components/@extended/AnimateButton.js Dosyayı Görüntüle

@@ -5,7 +5,7 @@ import { motion } from 'framer-motion';

// ==============================|| ANIMATION BUTTON ||============================== //

export default function AnimateButton({ children, type }) {
export default function AnimateButton({ children, type = 'scale' }) {
switch (type) {
case 'rotate': // only available in paid version
case 'slide': // only available in paid version
@@ -23,7 +23,3 @@ AnimateButton.propTypes = {
children: PropTypes.node,
type: PropTypes.oneOf(['slide', 'scale', 'rotate'])
};

AnimateButton.defaultProps = {
type: 'scale'
};

+ 23
- 11
src/components/AdminLogo/index.js Dosyayı Görüntüle

@@ -15,24 +15,36 @@ import {
checkSysEnv
} from "utils/Utils";

import {useIntl} from "react-intl";
// ==============================|| MAIN LOGO ||============================== //

const LogoSection = ({ sx, to }) => {
const { defaultId } = useSelector((state) => state.menu);
const dispatch = useDispatch();
const intl = useIntl();
return (
<Stack direction="column" justifyContent="center" alignItems="center" >
<ButtonBase
disableRipple
component={Link}
onClick={() => dispatch(activeItem({ openItem: [defaultId] }))}
to={!to ? config.defaultPath : to}
sx={sx}
>
<ButtonBase
disableRipple
component={Link}
onClick={() => dispatch(activeItem({ openItem: [defaultId] }))}
to={!to ? config.defaultPath : to}
aria-label={intl.formatMessage({ id: "PNSPS", defaultMessage: "PNSPS" })}
sx={{
...sx,
/* ✅ WCAG 2.4.7 focus indicator */
'&:focus-visible': {
outline: '3px solid #0C489E',
outlineOffset: '2px',
borderRadius: '6px'
}
}}
>
<Stack direction="column" justifyContent="center" alignItems="center" >
<Logo />
</ButtonBase>
<span style={{ color: checkSysEnv()!=''?'red':'#0C489E'}} id="systemTitle">PNSPS</span>
</Stack>
<span style={{ color: checkSysEnv()!=''?'red':'#0C489E'}} id="systemTitle">PNSPS</span>
</Stack>
</ButtonBase>

);
};


+ 11
- 3
src/components/AutoLogoutProvider.js Dosyayı Görüntüle

@@ -1,8 +1,9 @@
import React, { createContext, useState, useEffect } from 'react';
import React, { createContext, useState, useEffect, useRef } from 'react';
import {useNavigate} from "react-router-dom";
import {useIdleTimer} from "react-idle-timer";
import { handleLogoutFunction } from 'auth/index';
import { useDispatch } from "react-redux";
import { useIntl } from "react-intl";
import {
isUserLoggedIn,
isGLDLoggedIn,
@@ -12,9 +13,11 @@ import {
const TimerContext = createContext();

const AutoLogoutProvider = ({ children }) => {
const intl = useIntl();
const [lastRequestTime, setLastRequestTime] = useState(Date.now());
const navigate = useNavigate();
const [logoutInterval, setLogoutInterval] = useState(1);
const idleLogoutTriggeredRef = useRef(false);
// const [remainingInterval] = useState(5);
const [state, setState] = useState('Active');
const dispatch = useDispatch()
@@ -93,8 +96,13 @@ const AutoLogoutProvider = ({ children }) => {
// console.log(remainingInterval * 60);
// console.log(logoutInterval * 60 * 1000 - timeElapsed)
if (timeElapsed >= logoutInterval * 60 * 1000) {
if(isUserLoggedIn()){
alert("登入驗證已過期,請重新登入。")
if (isUserLoggedIn() && !idleLogoutTriggeredRef.current) {
idleLogoutTriggeredRef.current = true;
// Skip alert if token-expiry (axios 401) already showed one, to avoid duplicate alerts
if (localStorage.getItem("expiredAlertShown") === null) {
localStorage.setItem("expiredAlertShown", "true");
alert(intl.formatMessage({ id: "autoLogout" }));
}
dispatch(handleLogoutFunction());
navigate('/login');
window.location.reload();


+ 62
- 12
src/components/FiDataGrid.js Dosyayı Görüntüle

@@ -1,5 +1,5 @@
// material-ui
import { useState, useEffect } from 'react';
import { useState, useEffect, useRef } from 'react';
import { Box } from "@mui/material";
import {
DataGrid, GridOverlay,
@@ -202,9 +202,49 @@ export function FiDataGrid({ rows, columns, sx, autoHeight = true,
});
}

const gridRootRef = useRef(null);

useEffect(() => {
const root = gridRootRef.current;
if (!root) return;

const sortText = intl.formatMessage({ id: "sort", defaultMessage: "Sort" });

const apply = () => {
// 1) Make ALL column headers tabbable (optional; DataGrid already manages focus well)
root
.querySelectorAll('.MuiDataGrid-columnHeaders [role="columnheader"]')
.forEach((el) => {
if (el.getAttribute("tabindex") !== "0") el.setAttribute("tabindex", "0");
});

// 2) Localize sort icon button label (handles "sort"/"Sort"/any old value)
const sortButtons = root.querySelectorAll(
'.MuiDataGrid-columnHeaders button.MuiIconButton-root'
);

sortButtons.forEach((btn) => {
const al = (btn.getAttribute("aria-label") || "").trim().toLowerCase();
const ti = (btn.getAttribute("title") || "").trim().toLowerCase();

// Only rewrite the ones that are the sort icon buttons
if (al === "sort" || ti === "sort") {
btn.setAttribute("aria-label", sortText);
btn.setAttribute("title", sortText);
}
});
};

apply();

const obs = new MutationObserver(apply);
obs.observe(root, { childList: true, subtree: true });

return () => obs.disconnect();
}, [intl]);

return (
<Box sx={containerSx}>
<Box sx={containerSx} ref={gridRootRef} role="table">
<DataGrid
{...props}
rows={_rows}
@@ -239,16 +279,26 @@ export function FiDataGrid({ rows, columns, sx, autoHeight = true,
? {
Pagination: () => (
<TablePagination
count={rowCount || 0}
page={page}
rowsPerPage={pageSize}
rowsPerPageOptions={_pageSizeOptions}
labelDisplayedRows={() =>
`${(_rows?.length ? page * pageSize + 1 : 0)}-${page * pageSize + (_rows?.length ?? 0)} ${intl.formatMessage({ id: "of" })} ${rowCount}`
}
labelRowsPerPage={intl.formatMessage({ id: "rowsPerPage" }) + ":"}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangePageSize}
component="div"
count={rowCount || 0}
page={page}
rowsPerPage={pageSize}
rowsPerPageOptions={_pageSizeOptions}
labelDisplayedRows={() =>
`${(_rows?.length ? page * pageSize + 1 : 0)}-${page * pageSize + (_rows?.length ?? 0)} ${intl.formatMessage({ id: "of" })} ${rowCount}`
}
labelRowsPerPage={intl.formatMessage({ id: "rowsPerPage" }) + ":"}
getItemAriaLabel={(type) => {
if (type === 'previous') {
return intl.formatMessage({ id: 'paginationPrev' });
}
if (type === 'next') {
return intl.formatMessage({ id: 'paginationNext' });
}
return '';
}}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangePageSize}
/>
),
}


+ 4
- 0
src/components/Logo/index.js Dosyayı Görüntüle

@@ -9,18 +9,22 @@ import { useDispatch, useSelector } from 'react-redux';
import Logo from './Logo';
import config from 'config';
import { activeItem } from 'store/reducers/menu';
import {useIntl} from "react-intl";

// ==============================|| MAIN LOGO ||============================== //

const LogoSection = ({ sx, to }) => {
const { defaultId } = useSelector((state) => state.menu);
const dispatch = useDispatch();
const intl = useIntl();

return (
<ButtonBase
disableRipple
component={Link}
onClick={() => dispatch(activeItem({ openItem: [defaultId] }))}
to={!to ? config.defaultPath : to}
aria-label={intl.formatMessage({ id: "PNSPS", defaultMessage: "PNSPS" })}
sx={sx}
>
<Logo />


+ 27
- 1
src/components/MainCard.js Dosyayı Görüntüle

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import { forwardRef } from 'react';
import omit from 'lodash/omit';

// material-ui
import { useTheme } from '@mui/material/styles';
@@ -8,6 +9,29 @@ import { Card, CardContent, CardHeader, Divider, Typography, Grid } from '@mui/m
// project import
import Highlighter from './third-party/Highlighter';

/** Props often mistaken for Card / Grid / sx — must not reach the underlying DOM node via `{...others}`. */
const PROPS_OMIT_FROM_CARD = [
'backgroundColor',
'bgcolor',
'xs',
'sm',
'md',
'lg',
'xl',
'item',
'container',
'spacing',
'direction',
'justify',
'alignItems',
'alignContent',
'flexWrap',
'wrap',
'zeroMinWidth',
'rowSpacing',
'columnSpacing'
];

// header style
const headerSX = {
p: 2.5,
@@ -38,6 +62,8 @@ const MainCard = forwardRef(
const theme = useTheme();
boxShadow = theme.palette.mode === 'dark' ? boxShadow || true : boxShadow;

const cardProps = omit(others, PROPS_OMIT_FROM_CARD);

return (
<Grid container direction="column"
// alignItems="center"
@@ -46,7 +72,7 @@ const MainCard = forwardRef(
<Card
elevation={elevation || 0}
ref={ref}
{...others}
{...cardProps}
sx={{
alignItems: "center",
border: border ? '1px solid' : 'none',


+ 21
- 8
src/components/MobileLogo/index.js Dosyayı Görüntüle

@@ -9,22 +9,35 @@ import { useDispatch, useSelector } from 'react-redux';
import Logo from './MobileLogo';
import config from 'config';
import { activeItem } from 'store/reducers/menu';
import {useIntl} from "react-intl";

// ==============================|| MAIN LOGO ||============================== //

const LogoSection = ({ sx, to }) => {
const intl = useIntl();

const { defaultId } = useSelector((state) => state.menu);
const dispatch = useDispatch();
return (
<ButtonBase
disableRipple
component={Link}
onClick={() => dispatch(activeItem({ openItem: [defaultId] }))}
to={!to ? config.defaultPath : to}
sx={sx}
>
<Logo />
</ButtonBase>
disableRipple
component={Link}
onClick={() => dispatch(activeItem({ openItem: [defaultId] }))}
to={!to ? config.defaultPath : to}
aria-label={intl.formatMessage({ id: "PNSPS" })}
sx={{
...sx,

/* WCAG 2.4.7 – visible keyboard focus */
'&:focus-visible': {
outline: '3px solid #0C489E',
outlineOffset: '2px',
borderRadius: '6px'
}
}}
>
<Logo />
</ButtonBase>
);
};



+ 33
- 16
src/components/cards/AuthFooter.js Dosyayı Görüntüle

@@ -2,6 +2,7 @@
import { useMediaQuery, Container, Link, Typography, Stack } from '@mui/material';
import bhkLogo from 'assets/images/BHK_logo_rgb_zh-hk.png';
import {FormattedMessage} from "react-intl";
import {useIntl} from "react-intl";
import {
isGLDLoggedIn,
} from "utils/Utils";
@@ -9,9 +10,14 @@ import {

const AuthFooter = () => {
const matchDownSM = useMediaQuery((theme) => theme.breakpoints.down('sm'));
const intl = useIntl();

const bhkAlt = intl.formatMessage({ id: "bhkLogoAlt" });
const wcagAlt = intl.formatMessage({ id: "wcagAaAlt" });

return (
<Container maxWidth= "xl" sx={{minHeight: '5vh'}}>
<Container maxWidth="xl" sx={{ minHeight: '5vh' }}>

<Stack
direction={matchDownSM ? 'column' : 'row'}
justifyContent={matchDownSM ? 'center' : 'flex-start'}
@@ -19,7 +25,11 @@ const AuthFooter = () => {
textAlign={matchDownSM ? 'center' : 'inherit'}
alignItems="center"
>
<Typography variant="subtitle2" color="secondary" component="span">
<Typography
variant="subtitle2"
component="span"
sx={{ color: '#4A4A4A' }}
>
2024 &copy; <FormattedMessage id="HKGLD" />
</Typography>
<Typography
@@ -44,22 +54,29 @@ const AuthFooter = () => {
</Typography>
</Stack>
<Stack direction={matchDownSM ? 'column' : 'row'} spacing={matchDownSM ? 1 : 3} textAlign={matchDownSM ? 'center' : 'inherit'} justifyContent={matchDownSM?"center":"flex-end"}>
{!isGLDLoggedIn()?
<a href="https://www.w3.org/WAI/WCAG2AA-Conformance"
title="Explanation of WCAG 2 Level AA conformance">
<img height="32" width="88"
src="https://www.w3.org/WAI/wcag2AA"
alt="Level AA conformance,
W3C WAI Web Content Accessibility Guidelines 2.0"/>
</a>:null
}

<a href="https://www.brandhk.gov.hk/zh-hk"
title="Brand Hong Kong">
<img src={bhkLogo} alt="logo" height="32" width="88"
{!isGLDLoggedIn()? (
<a
href="https://www.w3.org/WAI/WCAG2AA-Conformance"
title="Explanation of WCAG 2 Level AA conformance"
>
<img
height="32"
width="88"
src="https://www.w3.org/WAI/wcag2AA"
alt={wcagAlt}
/>
</a>
</Stack>
) : null}

<a href="https://www.brandhk.gov.hk/zh-hk" title="Brand Hong Kong">
<img
src={bhkLogo}
alt={bhkAlt}
height="32"
width="88"
/>
</a>
</Stack>
</Container>
);
};


+ 3
- 2
src/components/iAmSmartButton.js Dosyayı Görüntüle

@@ -1,5 +1,6 @@
// material-ui
import {useState, useEffect} from 'react';
import { useIntl } from 'react-intl';
import iAmSmartICon from 'assets/images/icons/icon_iAmSmart.png';
import {
Button,
@@ -9,7 +10,7 @@ import {
// ==============================|| EVENT TABLE ||============================== //

export function IAmSmartButton({ label, onClickFun, fullWidth }) {
const intl = useIntl();
const [_label, set_label] = useState("");
useEffect(()=>{
@@ -23,7 +24,7 @@ export function IAmSmartButton({ label, onClickFun, fullWidth }) {
}

return (
<Button onClick={()=>doOnClick()} sx={{textTransform: 'none'}} color="iAmSmart" fullWidth={fullWidth} size="large" variant="outlined" startIcon={<img src={iAmSmartICon} alt="iAM Smart" width="30" />}>
<Button onClick={()=>doOnClick()} sx={{textTransform: 'none'}} color="iAmSmart" fullWidth={fullWidth} size="large" variant="outlined" startIcon={<img src={iAmSmartICon} alt={intl.formatMessage({ id: 'iAmSmartAlt' })} width="30" />}>
<Typography variant="h5">
{_label}
</Typography>


+ 42
- 0
src/components/usePageTitle.js Dosyayı Görüntüle

@@ -0,0 +1,42 @@
import { useEffect } from "react";
import { useIntl } from "react-intl";

export default function usePageTitle(messageIdOrText) {
const intl = useIntl();

useEffect(() => {
let pageTitle;
let systemName;
let gldName;

// If string looks like an intl id, try translate
try {
pageTitle = intl.formatMessage({ id: messageIdOrText });
systemName = intl.formatMessage({ id: "PNSPS_fullname" });
gldName = intl.formatMessage({ id: "HKGLD" });
} catch {
pageTitle = messageIdOrText;
}

const fullTitle = `${pageTitle} - ${systemName} | ${gldName}`;

// Update document title (tab title)
document.title = fullTitle;

// Update <meta name="title"> and <meta name="description"> so they're language-dependent too
const metaTitle = document.querySelector('meta[name="title"]');
if (metaTitle) {
metaTitle.setAttribute("content", fullTitle);
}

const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) {
metaDescription.setAttribute("content", fullTitle);
}

// Keep <html lang="..."> in sync with current locale
if (document.documentElement) {
document.documentElement.lang = intl.locale || "en";
}
}, [messageIdOrText, intl]);
}

+ 2
- 1
src/index.js Dosyayı Görüntüle

@@ -1,7 +1,8 @@
import { StrictMode, useEffect, useContext } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import "./assets/style/styles.css"
import './assets/fonts.css';
import './assets/style/styles.css';

// scroll bar
import 'simplebar/src/simplebar.css';


+ 3
- 1
src/layout/MainLayout/Drawer/index.js Dosyayı Görüntüle

@@ -4,6 +4,7 @@ import { useMemo } from 'react';
// material-ui
import { useTheme } from '@mui/material/styles';
import { Box, Drawer, useMediaQuery } from '@mui/material';
import { useIntl } from 'react-intl';

// project import
import DrawerHeader from './DrawerHeader';
@@ -15,6 +16,7 @@ import { drawerWidth } from 'config';

const MainDrawer = ({ open, handleDrawerToggle, window }) => {
const theme = useTheme();
const intl = useIntl();
const matchDownMD = useMediaQuery(theme.breakpoints.down('lg'));

// responsive drawer container
@@ -25,7 +27,7 @@ const MainDrawer = ({ open, handleDrawerToggle, window }) => {
const drawerHeader = useMemo(() => <DrawerHeader open={open} />, [open]);

return (
<Box component="nav" sx={{ flexShrink: { md: 0 }, zIndex: 1300 }} aria-label="mailbox folders">
<Box component="nav" sx={{ flexShrink: { md: 0 }, zIndex: 1300 }} aria-label={intl.formatMessage({ id: 'ariaMailboxFolders' })}>
{!matchDownMD ? (
<MiniDrawerStyled variant="permanent" open={open}>
{drawerHeader}


+ 22
- 10
src/layout/MainLayout/Header/HeaderContent/LocaleSelector.js Dosyayı Görüntüle

@@ -16,7 +16,7 @@ import {

import Transitions from 'components/@extended/Transitions';
import LanguageIcon from '@mui/icons-material/Language';
import {FormattedMessage} from "react-intl";
import {FormattedMessage, useIntl} from "react-intl";
import * as React from "react";
import LocaleContext from "components/I18nProvider";

@@ -27,6 +27,8 @@ const LocaleSelector = () => {
const matchesXs = useMediaQuery(theme.breakpoints.down('md'));
const { setLocale } = useContext(LocaleContext);

const intl = useIntl();

const anchorRef = useRef(null);
const [open, setOpen] = useState(false);
const handleToggle = () => {
@@ -47,16 +49,26 @@ const LocaleSelector = () => {
return (
<Box sx={{ flexShrink: 0, ml: 0.75 }}>
<IconButton
disableRipple
color="secondary"
sx={{ color: 'text.primary', bgcolor: open ? iconBackColorOpen : iconBackColor }}
aria-label="open profile"
ref={anchorRef}
aria-controls={open ? 'profile-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
disableRipple
color="secondary"
sx={{
color: 'text.primary',
bgcolor: open ? iconBackColorOpen : iconBackColor,

/* ✅ WCAG 2.4.7 focus indicator */
'&:focus-visible': {
outline: '3px solid #0C489E',
outlineOffset: '2px',
borderRadius: '6px'
}
}}
aria-label={intl.formatMessage({id: 'openLanguage'})}
ref={anchorRef}
aria-controls={open ? 'profile-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
>
<LanguageIcon />
<LanguageIcon />
</IconButton>
<Popper
placement={matchesXs ? 'bottom' : 'bottom-end'}


+ 20
- 13
src/layout/MainLayout/Header/HeaderContent/MobileSection.js Dosyayı Görüntüle

@@ -45,19 +45,26 @@ const MobileSection = () => {
<>
<Box sx={{ flexShrink: 0, ml: 0.75 }}>
<IconButton
component="span"
disableRipple
sx={{
bgcolor: open ? 'grey.300' : 'grey.100'
}}
ref={anchorRef}
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
color="inherit"
>
<MoreOutlined />
</IconButton>
component="span"
disableRipple
sx={{
bgcolor: open ? 'grey.300' : 'grey.100',

/* WCAG 2.4.7 – visible keyboard focus */
'&:focus-visible': {
outline: '3px solid #0C489E',
outlineOffset: '2px',
borderRadius: '6px'
}
}}
ref={anchorRef}
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
color="inherit"
>
<MoreOutlined />
</IconButton>
</Box>
<Popper
placement="bottom-end"


+ 16
- 6
src/layout/MainLayout/Header/HeaderContent/Notification.js Dosyayı Görüntüle

@@ -71,17 +71,27 @@ const Notification = () => {
<IconButton
disableRipple
color="secondary"
sx={{ color: 'text.primary', bgcolor: open ? iconBackColorOpen : iconBackColor }}
aria-label="open profile"
sx={{
color: 'text.primary',
bgcolor: open ? iconBackColorOpen : iconBackColor,

/* ✅ WCAG 2.4.7 focus indicator */
'&:focus-visible': {
outline: '3px solid #0C489E',
outlineOffset: '2px',
borderRadius: '6px'
}
}}
aria-label={intl.formatMessage({id: 'openLanguage'})}
ref={anchorRef}
aria-controls={open ? 'profile-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
>
<Badge badgeContent={4} color="primary">
<BellOutlined />
</Badge>
</IconButton>
<Badge badgeContent={4} color="primary">
<BellOutlined />
</Badge>
</IconButton>
<Popper
placement={matchesXs ? 'bottom' : 'bottom-end'}
open={open}


+ 4
- 2
src/layout/MainLayout/Header/HeaderContent/Profile/index.js Dosyayı Görüntüle

@@ -33,6 +33,7 @@ import { LogoutOutlined,
import { handleLogoutFunction } from 'auth/index';
import {useNavigate} from "react-router-dom";
import {useDispatch} from "react-redux";
import { useIntl } from 'react-intl';
import AccountCircleIcon from '@mui/icons-material/AccountCircle';

// tab panel wrapper
@@ -61,6 +62,7 @@ TabPanel.propTypes = {

const Profile = () => {
const theme = useTheme();
const intl = useIntl();
const navigate = useNavigate()
const dispatch = useDispatch()

@@ -101,7 +103,7 @@ const Profile = () => {
borderRadius: 1,
'&:hover': { bgcolor: 'secondary.lighter' }
}}
aria-label="open profile"
aria-label={intl.formatMessage({id: 'openLanguage'})}
ref={anchorRef}
aria-controls={open ? 'profile-grow' : undefined}
aria-haspopup="true"
@@ -170,7 +172,7 @@ const Profile = () => {
{/* {open && (
<>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs variant="fullWidth" value={value} onChange={handleChange} aria-label="profile tabs">
<Tabs variant="fullWidth" value={value} onChange={handleChange} aria-label={intl.formatMessage({ id: 'ariaProfileTabs' })}>
<Tab
sx={{
display: 'flex',


+ 824
- 745
src/layout/MainLayout/Header/index.js
Dosya farkı çok büyük olduğundan ihmal edildi
Dosyayı Görüntüle


+ 1
- 1
src/layout/MainLayout/index.js Dosyayı Görüntüle

@@ -62,7 +62,7 @@ const MainLayout = () => {
<Box sx={{backgroundColor:'#ffffff', display: 'flex', width: '100%', flexDirection: "column", paddingTop: { xs: "5px", sm: "25px", md: "43px" }}}>
<Header/>
{/* <Drawer open={open} handleDrawerToggle={handleDrawerToggle} /> */}
<Box style={{ width: '100%', flexGrow: 1 } } sx={{ paddingTop: "38px" }}>
<Box style={{ width: '100%', flexGrow: 1 }} sx={{ paddingTop: "36px" }}>
{/* <Toolbar /> */}
{/* <Breadcrumbs navigation={navigation} title /> */}
<Outlet />


+ 3
- 3
src/pages/Announcement/Details/AnnouncementForm.js Dosyayı Görüntüle

@@ -143,7 +143,7 @@ const AnnouncementForm = ({ loadedData }) => {
</Grid>
</Grid>

<Grid item xs={12} md={12} sx={{ mt: 2 }}><Divider fullWidth></Divider></Grid>
<Grid item xs={12} md={12} sx={{ mt: 2 }}><Divider sx={{ width: '100%' }} /></Grid>
<Grid item xs={12} md={12}><Typography variant="h5">English</Typography></Grid>
<Grid item xs={12} md={12} >
<Grid container alignItems={"center"} xs={12} sm={12} md={12} lg={12} sx={{ mb: 2 }}>
@@ -202,7 +202,7 @@ const AnnouncementForm = ({ loadedData }) => {
</Grid>
</Grid>

<Grid item xs={12} md={12} sx={{ mt: 2 }}><Divider fullWidth></Divider></Grid>
<Grid item xs={12} md={12} sx={{ mt: 2 }}><Divider sx={{ width: '100%' }} /></Grid>
<Grid item xs={12} md={12}><Typography variant="h5">Traditional Chinese</Typography></Grid>
<Grid item xs={12} md={12}>
<Grid container alignItems={"center"} xs={12} sm={12} md={12} lg={12} sx={{ mb: 2 }}>
@@ -263,7 +263,7 @@ const AnnouncementForm = ({ loadedData }) => {



<Grid item xs={12} md={12} sx={{ mt: 2 }}><Divider fullWidth></Divider></Grid>
<Grid item xs={12} md={12} sx={{ mt: 2 }}><Divider sx={{ width: '100%' }} /></Grid>
<Grid item xs={12} md={12}><Typography variant="h5">Simplified Chinese</Typography></Grid>
<Grid item xs={12} md={12}>
<Grid container alignItems={"center"} xs={12} sm={12} md={12} lg={12} sx={{ mb: 2 }}>


+ 4
- 2
src/pages/Announcement/Search_Public/SearchForm.js Dosyayı Görüntüle

@@ -116,7 +116,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
<Grid item xs={12} s={6} md={6} lg={4} sx={{ ml: 3, mr: 3, mb: 3 }}>
<Grid container>
<Grid item xs={5.25} s={5.25} md={5.25} lg={5.5}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateFrom"
@@ -148,7 +148,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
</Grid>

<Grid item xs={5.25} s={5.25} md={5.25} lg={5.5}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateTo"
@@ -195,7 +195,9 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
<Grid item sx={{ ml: 3 }}>
<Button
variant="contained"
color="cancel"
onClick={resetForm}
aria-label={intl.formatMessage({ id: 'reset' })}
>
<FormattedMessage id="reset"></FormattedMessage>
</Button>


+ 3
- 2
src/pages/Announcement/Search_Public/index.js Dosyayı Görüntüle

@@ -15,6 +15,7 @@ const EventTable = Loadable(React.lazy(() => import('./DataGrid')));
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
import { FormattedMessage } from "react-intl";
import { getSearchCriteria } from "auth/utils";
import usePageTitle from "components/usePageTitle";

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
@@ -29,7 +30,7 @@ const BackgroundHead = {
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const UserSearchPage_Individual = () => {
usePageTitle("announcement");
const [searchCriteria, setSearchCriteria] = React.useState({});
const [onReady, setOnReady] = React.useState(false);
const [onGridReady, setGridOnReady] = React.useState(false);
@@ -74,7 +75,7 @@ const UserSearchPage_Individual = () => {
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{ "textShadow": "0px 0px 25px #0C489E" }}><FormattedMessage id="announcement" /></Typography>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{ "textShadow": "0px 0px 25px #0C489E" }}><FormattedMessage id="announcement" /></Typography>
</Stack>
</div>
</Grid>


+ 16
- 11
src/pages/AuditLog/AuditLogSearchForm.js Dosyayı Görüntüle

@@ -43,7 +43,7 @@ const AuditLogSearchForm = ({ applySearch, searchCriteria, onGridReady}) => {
const marginBottom = 2.5;

const { reset, register, handleSubmit } = useForm()
const { reset, register, handleSubmit, getValues } = useForm()

React.useEffect(() => {
setFromDateValue(minDate);
@@ -53,21 +53,26 @@ const AuditLogSearchForm = ({ applySearch, searchCriteria, onGridReady}) => {
setToDateValue(maxDate);
}, [maxDate]);

const onSubmit = (data) => {
/** Same filter fields as the list API; must reflect current form/UI state (not parent `searchCriteria`). */
const getCurrentFilterParams = () => {
let sentDateFrom = "";
let sentDateTo = "";

if (fromDateValue != "dd / mm / yyyy" && toDateValue != "dd / mm / yyyy") {
sentDateFrom = DateUtils.dateValue(fromDateValue)
sentDateTo = DateUtils.dateValue(toDateValue)
sentDateFrom = DateUtils.dateValue(fromDateValue);
sentDateTo = DateUtils.dateValue(toDateValue);
}

const temp = {
username: data.userName,
return {
username: getValues("userName"),
modifiedTo: sentDateTo,
modifiedFrom: sentDateFrom,
start:0,
limit:10
};
};

const onSubmit = () => {
const temp = {
...getCurrentFilterParams(),
start: 0,
limit: 10,
};
applySearch(temp);
};
@@ -81,7 +86,7 @@ const AuditLogSearchForm = ({ applySearch, searchCriteria, onGridReady}) => {
setOnDownload(true)
HttpUtils.fileDownload({
url: UrlUtils.AUDIT_LOG_EXPORT,
params: searchCriteria,
params: getCurrentFilterParams(),
onResponse:()=>{
setOnDownload(false)
},


+ 11
- 4
src/pages/DemandNote/Create/SearchForm.js Dosyayı Görüntüle

@@ -13,7 +13,7 @@ import * as DateUtils from "utils/DateUtils";
import * as UrlUtils from "utils/ApiPathConst";
import * as HttpUtils from "utils/HttpUtils";
import { useNavigate } from "react-router-dom";
import { notifyDownloadSuccess } from 'utils/CommonFunction';
import { notifyActionError } from 'utils/CommonFunction';
import { PNSPS_BUTTON_THEME } from "../../../themes/buttonConst";
import { ThemeProvider } from "@emotion/react";
import { useIntl } from "react-intl";
@@ -118,8 +118,11 @@ const SearchPublicNoticeForm = ({ applySearch, issueComboData, _paymentCount, _p
params: {
"dnIdList": dnIdList
},
onSuccess: function () {
notifyDownloadSuccess();
onResponse: function () {
// 200: browser handles save; no success toast
},
onError: function () {
notifyActionError(intl.formatMessage({ id: 'downloadFailed' }));
}
});
}
@@ -186,6 +189,10 @@ const SearchPublicNoticeForm = ({ applySearch, issueComboData, _paymentCount, _p
}}
/>
)}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
/>
</Grid>
<Grid item >
@@ -194,7 +201,7 @@ const SearchPublicNoticeForm = ({ applySearch, issueComboData, _paymentCount, _p
variant="contained"
onClick={onSubmit}
color="success"
minWidth={150}
sx={{ minWidth: 150 }}
>
Create
</Button>


+ 7
- 3
src/pages/DemandNote/Details/ApplicationDetailCard.js Dosyayı Görüntüle

@@ -15,11 +15,12 @@ import * as StatusUtils from "utils/statusUtils/PublicNoteStatusUtils";
import * as HttpUtils from "utils/HttpUtils";

import DownloadIcon from '@mui/icons-material/Download';
import { notifyDownloadSuccess } from 'utils/CommonFunction';
import { notifyActionError } from 'utils/CommonFunction';
import { useIntl } from 'react-intl';

// ==============================|| DASHBOARD - DEFAULT ||============================== //
const ApplicationDetailCard = ({ data }) => {
const intl = useIntl();
const [appDetail, setAppDetails] = React.useState({});

React.useEffect(() => {
@@ -33,8 +34,11 @@ const ApplicationDetailCard = ({ data }) => {
fileId: appDetail.appFileId,
skey: appDetail.appSkey,
filename: appDetail.appFilename,
onResponse: function () {},
onError: function () {
notifyActionError(intl.formatMessage({ id: 'downloadFailed' }));
}
});
notifyDownloadSuccess();
};

return (


+ 6
- 4
src/pages/DemandNote/Details/DnDetailCard.js Dosyayı Görüntüle

@@ -14,12 +14,13 @@ import Loadable from 'components/Loadable';
const MainCard = Loadable(React.lazy(() => import('components/MainCard')));

import DownloadIcon from '@mui/icons-material/Download';
import { notifyDownloadSuccess } from 'utils/CommonFunction';
import { notifyActionError } from 'utils/CommonFunction';
import { useIntl } from 'react-intl';


// ==============================|| DASHBOARD - DEFAULT ||============================== //
const DnDetailCard = ({ data }) => {
const intl = useIntl();
const [dnData, setDnData] = React.useState({});

React.useEffect(() => {
@@ -33,8 +34,9 @@ const DnDetailCard = ({ data }) => {
fileId: dnData.fileId,
skey: dnData.skey,
filename: dnData.filename,
onResponse: function () {
notifyDownloadSuccess();
onResponse: function () {},
onError: function () {
notifyActionError(intl.formatMessage({ id: 'downloadFailed' }));
}
});
};


+ 5
- 1
src/pages/DemandNote/Export/SearchForm.js Dosyayı Görüntüle

@@ -187,6 +187,10 @@ const SearchPublicNoticeForm = ({ applySearch, issueComboData }) => {
}}
/>
)}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
/>
</Grid>
@@ -197,7 +201,7 @@ const SearchPublicNoticeForm = ({ applySearch, issueComboData }) => {
onClick={onSubmit}
color="success"
disabled={waitDownload}
minWidth={150}
sx={{ minWidth: 150 }}
>
Export
</Button>


+ 11
- 8
src/pages/DemandNote/Search/DataGrid.js Dosyayı Görüntüle

@@ -13,7 +13,7 @@ import * as FormatUtils from "utils/FormatUtils";
import * as StatusUtils from "utils/statusUtils/DnStatus";
import { useNavigate } from "react-router-dom";
import { FiDataGrid } from "components/FiDataGrid";
import { notifyDownloadSuccess } from 'utils/CommonFunction';
import { notifyActionError } from 'utils/CommonFunction';
import {
DEMAND_NOTE_EXPORT,
DEMAND_NOTE_SEND,
@@ -26,10 +26,11 @@ import * as HttpUtils from "utils/HttpUtils";
import { PNSPS_BUTTON_THEME } from "themes/buttonConst";
import { ThemeProvider } from "@emotion/react";
import { isGrantedAny } from "auth/utils";
import { useIntl } from "react-intl";
// ==============================|| EVENT TABLE ||============================== //

export default function SearchDemandNote({ applySearch, searchCriteria, applyGridOnReady }) {
const intl = useIntl();
const [isConfirmPopUp, setConfirmPopUp] = useState(false);
const [isRevokePopUp, setRevokePopUp] = useState(false);
const [isSendPopUp, setSendPopUp] = useState(false);
@@ -80,8 +81,9 @@ export default function SearchDemandNote({ applySearch, searchCriteria, applyGri
params: {
dnIdList: idList
},
onSuccess: function () {
notifyDownloadSuccess();
onResponse: function () {},
onError: function () {
notifyActionError(intl.formatMessage({ id: 'downloadFailed' }));
}
});
}
@@ -92,11 +94,12 @@ export default function SearchDemandNote({ applySearch, searchCriteria, applyGri
fileId: params.row.fileId,
skey: params.row.skey,
filename: params.row.filename,
onResponse:()=>{
setOnDownload(false)
onResponse: () => {
setOnDownload(false);
},
onError:()=>{
setOnDownload(false)
onError: () => {
setOnDownload(false);
notifyActionError(intl.formatMessage({ id: 'downloadFailed' }));
}
});
};


+ 13
- 1
src/pages/DemandNote/Search/SearchForm.js Dosyayı Görüntüle

@@ -224,6 +224,10 @@ const SearchDemandNoteForm = ({ applySearch, orgComboData, searchCriteria, issue
}}
/>
)}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
/>
</Grid>

@@ -282,6 +286,10 @@ const SearchDemandNoteForm = ({ applySearch, orgComboData, searchCriteria, issue
{params.children}
</Grid>
)}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
/>
</Grid>
: <></>
@@ -435,7 +443,7 @@ const SearchDemandNoteForm = ({ applySearch, orgComboData, searchCriteria, issue
'& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
'& .MuiOutlinedInput-root': { height: 40 }
}}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
renderInput={(params) => (
<TextField
{...params}
@@ -445,6 +453,10 @@ const SearchDemandNoteForm = ({ applySearch, orgComboData, searchCriteria, issue
}}
/>
)}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
/>
</Grid>



+ 1
- 2
src/pages/DemandNote/Search_Public/DataGrid.js Dosyayı Görüntüle

@@ -66,8 +66,7 @@ export default function SearchDemandNote({ searchCriteria, applyGridOnReady,appl
width: isMdOrLg ? 'auto' : 175,
flex: isMdOrLg ? 1 : undefined,
renderCell: (params) => {

return [StatusUtils.getStatus_i18n(params, locale) ]
return StatusUtils.getStatus_i18n(params, locale);
},
},
{


+ 11
- 5
src/pages/DemandNote/Search_Public/SearchForm.js Dosyayı Görüntüle

@@ -180,6 +180,10 @@ const SearchDemandNoteForm = ({ applySearch, searchCriteria, issueComboData, onG
}}
/>
)}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
/>
</Grid>

@@ -210,7 +214,7 @@ const SearchDemandNoteForm = ({ applySearch, searchCriteria, issueComboData, onG
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateFrom"
@@ -237,7 +241,7 @@ const SearchDemandNoteForm = ({ applySearch, searchCriteria, issueComboData, onG
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateTo"
@@ -288,11 +292,13 @@ const SearchDemandNoteForm = ({ applySearch, searchCriteria, issueComboData, onG
<TextField
{...params}
label={intl.formatMessage({ id: 'status' })}
InputLabelProps={{ shrink: true }}
/>
)}
InputLabelProps={{
shrink: true
}}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
/>
</Grid>



+ 3
- 2
src/pages/DemandNote/Search_Public/index.js Dosyayı Görüntüle

@@ -18,6 +18,7 @@ const SearchForm = Loadable(React.lazy(() => import('./SearchForm')));
const EventTable = Loadable(React.lazy(() => import('./DataGrid')));
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
import {FormattedMessage} from "react-intl";
import usePageTitle from "components/usePageTitle";

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
@@ -32,7 +33,7 @@ const BackgroundHead = {
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const SearchPage_DemandNote_Pub = () => {
usePageTitle("paymentInfoRecord");
const [orgCombo, setOrgCombo] = React.useState([]);
const [issueCombo, setIssueCombo] = React.useState([]);
const [searchCriteria, setSearchCriteria] = React.useState({});
@@ -101,7 +102,7 @@ const SearchPage_DemandNote_Pub = () => {
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
<FormattedMessage id="paymentInfoRecord" />
</Typography>
</Stack>


+ 2
- 4
src/pages/GFMIS/SearchForm.js Dosyayı Görüntüle

@@ -180,7 +180,7 @@ const SearchPublicNoticeForm = ({ applySearch, generateXML, searchCriteria, onGr
filterOptions={(options) => options}
options={ComboData.payMethod}
value={payMethod}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
inputValue={payMethod?.label ? payMethod?.label : ""}
onChange={(event, newValue) => {
if(newValue==null){
@@ -197,11 +197,9 @@ const SearchPublicNoticeForm = ({ applySearch, generateXML, searchCriteria, onGr
renderInput={(params) => (
<TextField {...params}
label="Payment Method"
InputLabelProps={{ shrink: true }}
/>
)}
InputLabelProps={{
shrink: true
}}
/>
</Grid>



+ 53
- 30
src/pages/GFMIS/index.js Dosyayı Görüntüle

@@ -4,6 +4,7 @@ import {
Typography,
Stack,
Button,
CircularProgress,
Dialog, DialogTitle, DialogContent, DialogActions,
} from '@mui/material';
import MainCard from "components/MainCard";
@@ -55,6 +56,8 @@ const Index = () => {
const [isPreviewLoading, setIsPreviewLoading] = React.useState(false);
const [isPopUp, setIsPopUp] = React.useState(false);
const [isXmlDialogSubmitting, setIsXmlDialogSubmitting] = React.useState(false);
const xmlDownloadInFlightRef = React.useRef(false);
const [downloadInput, setDownloadInput] = React.useState();
const [selectedIds, setSelectedIds] = React.useState([]);

@@ -66,6 +69,13 @@ const Index = () => {
setInputDateValue(inputDate);
}, [inputDate]);

React.useEffect(() => {
if (!isPopUp) {
xmlDownloadInFlightRef.current = false;
setIsXmlDialogSubmitting(false);
}
}, [isPopUp]);

React.useEffect(() => {
setOnReady(true);
}, [searchCriteria]);
@@ -94,66 +104,61 @@ const Index = () => {


function downloadXML() {
console.log(selectedIds.join(','))
setIsPopUp(false)
if (xmlDownloadInFlightRef.current) return;
xmlDownloadInFlightRef.current = true;
console.log(selectedIds.join(','));
setIsXmlDialogSubmitting(true);
let sentDateFrom = "";
if (inputDateValue != "dd / mm / yyyy") {
sentDateFrom = DateUtils.dateValue(inputDateValue)
sentDateFrom = DateUtils.dateValue(inputDateValue);
}
HttpUtils.get({
url: GEN_GFMIS_XML + "/today",
params:{
params: {
dateTo: downloadInput.dateTo,
dateFrom: downloadInput.dateFrom,
inputDate: sentDateFrom,
paymentId: selectedIds.join(',')
},
onSuccess: (responseData) => {
// console.log(responseData)
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(responseData, 'application/xml');
// Get the DCBHeader element
const dcbHeader = xmlDoc.querySelector("DCBHeader");
// Get the Receipt and Allocation elements

const receiptElement = dcbHeader.querySelector("Receipt");
const allocationElement = dcbHeader.querySelector("Allocation");
const paymentMethodElements = Array.from(dcbHeader.querySelectorAll("PaymentMethod"));

// Remove existing elements from DCBHeader
dcbHeader.innerHTML = "";
dcbHeader.appendChild(receiptElement);
dcbHeader.appendChild(allocationElement);
if (paymentMethodElements) {
paymentMethodElements.forEach((paymentMethodElement) => {
dcbHeader.appendChild(paymentMethodElement);
});
dcbHeader.appendChild(paymentMethodElement);
});
}
const updatedXmlString = new XMLSerializer().serializeToString(xmlDoc);
const filename = xmlDoc.querySelector('FileHeader').getAttribute('H_Filename');
// console.log(updatedXmlString)
const blob = new Blob([updatedXmlString], { type: 'application/xml' });
// Create a download link
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = filename+'.xml';
// Append the link to the document body
link.download = filename + '.xml';

document.body.appendChild(link);
// Programmatically click the link to trigger the download
link.click();
// Clean up the link
document.body.removeChild(link);
setIsPopUp(false);
},
onFinally: () => {
xmlDownloadInFlightRef.current = false;
setIsXmlDialogSubmitting(false);
}
});
// open(UrlUtils.GEN_GFMIS_XML + "/today?online=true")
}
});
}


function applySearch(input) {
@@ -263,7 +268,11 @@ const Index = () => {
</Grid>
<Dialog
open={isPopUp}
onClose={() => setIsPopUp(false)}
onClose={() => {
if (isXmlDialogSubmitting) return;
setIsPopUp(false);
}}
disableEscapeKeyDown={isXmlDialogSubmitting}
PaperProps={{
sx: {
minWidth: '40vw',
@@ -300,8 +309,22 @@ const Index = () => {
</LocalizationProvider>
</DialogContent>
<DialogActions>
<Button onClick={() => setIsPopUp(false)}><Typography variant="h5">Cancel</Typography></Button>
<Button onClick={() => downloadXML()}><Typography variant="h5">Confirm</Typography></Button>
<Button
onClick={() => {
if (isXmlDialogSubmitting) return;
setIsPopUp(false);
}}
disabled={isXmlDialogSubmitting}
>
<Typography variant="h5">Cancel</Typography>
</Button>
<Button
onClick={() => downloadXML()}
disabled={isXmlDialogSubmitting}
startIcon={isXmlDialogSubmitting ? <CircularProgress color="inherit" size={20} /> : null}
>
<Typography variant="h5">Confirm</Typography>
</Button>
</DialogActions>
</Dialog>
</Grid>


+ 5
- 1
src/pages/GazetteIssue/ExportForm.js Dosyayı Görüntüle

@@ -76,7 +76,11 @@ const SearchGazetteIssueForm = ({ applyExport, comboData, waitDownload}) => {
// defaultValue={selectedYear}
options={comboList}
// disabled={checkCountry}
getOptionLabel={(option) => option.label ? option.label : ""}
getOptionLabel={(option) =>
option != null && typeof option === "object" && option.label != null
? String(option.label)
: ""
}
onChange={(event, newValue) => {
setSelectedYear(newValue);
}}


+ 5
- 1
src/pages/GazetteIssue/SearchForm.js Dosyayı Görüntüle

@@ -74,7 +74,11 @@ const SearchGazetteIssueForm = ({ applySearch, comboData, onGridReady}) => {
// defaultValue={selectedYear}
options={comboList}
// disabled={checkCountry}
getOptionLabel={(option) => option.label ? option.label : ""}
getOptionLabel={(option) =>
option != null && typeof option === "object" && option.label != null
? String(option.label)
: ""
}
onChange={(event, newValue) => {
setSelectedYear(newValue);
}}


+ 22
- 5
src/pages/GazetteIssue/index.js Dosyayı Görüntüle

@@ -31,10 +31,12 @@ import { ThemeProvider } from "@emotion/react";
import { dateStr_Year } from "utils/DateUtils";
import { notifySaveSuccess } from 'utils/CommonFunction';
import { isGrantedAny } from "auth/utils";
import { useIntl } from 'react-intl';

// ==============================|| DASHBOARD - DEFAULT ||============================== //

const Index = () => {
const intl = useIntl();
const [comboData, setComboData] = React.useState([]);
const [holidayComboData, setHolidayComboData] = React.useState([]);
const [onReady, setOnReady] = React.useState(false);
@@ -50,6 +52,7 @@ const Index = () => {
const [waitDownload, setWaitDownload] = React.useState(false);
const [isWarningPopUp, setIsWarningPopUp] = React.useState(false);
const [warningText, setWarningText] = React.useState("");
const fileInputRef = React.useRef(null);

React.useEffect(() => {
setOnSearchReady(false);
@@ -184,13 +187,27 @@ const Index = () => {
<Stack direction="row" justifyContent="flex-start" alignItems="center" spacing={2} sx={{ ml: 2, mt: 1 }}>
<ThemeProvider theme={PNSPS_LONG_BUTTON_THEME}>
<Button
component="label"
variant="contained"
size="large"
disabled={waitImport}
type="button"
onClick={() => {
if (fileInputRef.current) {
fileInputRef.current.click();
}
}}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
if (fileInputRef.current) {
fileInputRef.current.click();
}
}
}}
>
<Typography variant="h5">Upload Files</Typography>
<input
</Button>
<input
id="uploadFileBtn"
name="file"
type="file"
@@ -198,9 +215,9 @@ const Index = () => {
hidden
disabled={waitImport}
onChange={readFile}
aria-label="Upload Excel file (.xlsx)"
/>
</Button>
aria-label={intl.formatMessage({ id: 'ariaUploadExcelFile' })}
ref={fileInputRef}
/>
</ThemeProvider>
</Stack>
</Grid>


+ 8
- 3
src/pages/Holiday/DataGrid.js Dosyayı Görüntüle

@@ -9,14 +9,19 @@ import { dateStr } from "utils/DateUtils";

// ==============================|| EVENT TABLE ||============================== //

function holidayRowsFromResponse(recordList) {
if (Array.isArray(recordList)) return recordList;
if (recordList && Array.isArray(recordList.records)) return recordList.records;
return [];
}

export default function HolidayTable({ recordList, applyGridOnReady }) {
const [rows, setRows] = React.useState(recordList);
const [rows, setRows] = React.useState(() => holidayRowsFromResponse(recordList));

// const navigate = useNavigate()

useEffect(() => {
// console.log(recordList)
setRows(recordList.records);
setRows(holidayRowsFromResponse(recordList));
}, [recordList]);

const columns = [


+ 9
- 5
src/pages/Holiday/SearchForm.js Dosyayı Görüntüle

@@ -17,7 +17,7 @@ import {ThemeProvider} from "@emotion/react";


const SearchHolidayForm = ({ applySearch, comboData, onGridReady}) => {
const [selectedYear, setSelectedYear] = React.useState([]);
const [selectedYear, setSelectedYear] = React.useState(null);
// const [defaultYear, setDefaultYear] = React.useState(searchCriteria.year);
const [comboList, setComboList] = React.useState([]);
// const [onReady, setOnReady] = React.useState(false);
@@ -27,7 +27,7 @@ const SearchHolidayForm = ({ applySearch, comboData, onGridReady}) => {
handleSubmit } = useForm()

const onSubmit = () => {
if (selectedYear !=null){
if (selectedYear != null) {
const temp = {
year: selectedYear.label,
};
@@ -40,8 +40,8 @@ const SearchHolidayForm = ({ applySearch, comboData, onGridReady}) => {
// console.log(comboData)
// const labelValue = comboData.find(obj => obj.label === searchCriteria.year);
// console.log(labelValue)
if(selectedYear.length == 0){
setSelectedYear(comboData[0])
if (!selectedYear) {
setSelectedYear(comboData[0]);
}
setComboList(comboData)
// setSelectedYear(searchCriteria.dateFrom)
@@ -74,7 +74,11 @@ const SearchHolidayForm = ({ applySearch, comboData, onGridReady}) => {
// defaultValue={selectedYear}
options={comboList}
// disabled={checkCountry}
getOptionLabel={(option) => option.label ? option.label : ""}
getOptionLabel={(option) =>
option != null && typeof option === "object" && option.label != null
? String(option.label)
: ""
}
onChange={(event, newValue) => {
setSelectedYear(newValue);
}}


+ 23
- 7
src/pages/Holiday/index.js Dosyayı Görüntüle

@@ -31,11 +31,12 @@ import { ThemeProvider } from "@emotion/react";
import { dateStr_Year } from "utils/DateUtils";
import { notifySaveSuccess } from 'utils/CommonFunction';
import { isGrantedAny } from "auth/utils";
import { useIntl } from 'react-intl';

// ==============================|| DASHBOARD - DEFAULT ||============================== //

const Index = () => {
const intl = useIntl();
const [record, setRecord] = React.useState([]);
const [comboData, setComboData] = React.useState([]);
const [onReady, setOnReady] = React.useState(false);
@@ -50,6 +51,7 @@ const Index = () => {
const [waitDownload, setWaitDownload] = React.useState(false);
const [isWarningPopUp, setIsWarningPopUp] = React.useState(false);
const [warningText, setWarningText] = React.useState("");
const fileInputRef = React.useRef(null);

React.useEffect(() => {
setOnSearchReady(false);
@@ -172,7 +174,7 @@ const Index = () => {
size="large"
disabled={waitDownload}
onClick={doExport}
aria-label="Export holiday template"
aria-label={intl.formatMessage({ id: 'ariaExportHolidayTemplate' })}
>
<Typography variant="h5">Export</Typography>
</Button>
@@ -180,13 +182,27 @@ const Index = () => {
{isGrantedAny(["MAINTAIN_GAZETTE_ISSUE"]) ?
<ThemeProvider theme={PNSPS_LONG_BUTTON_THEME}>
<Button
component="label"
variant="contained"
size="large"
disabled={waitImport}
type="button"
onClick={() => {
if (fileInputRef.current) {
fileInputRef.current.click();
}
}}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
if (fileInputRef.current) {
fileInputRef.current.click();
}
}
}}
>
<Typography variant="h5">Upload Files</Typography>
<input
</Button>
<input
id="uploadFileBtn"
name="file"
type="file"
@@ -194,9 +210,9 @@ const Index = () => {
hidden
disabled={waitImport}
onChange={readFile}
aria-label="Upload Excel file (.xlsx)"
/>
</Button>
aria-label={intl.formatMessage({ id: 'ariaUploadExcelFile' })}
ref={fileInputRef}
/>
</ThemeProvider>
: null
}


+ 82
- 16
src/pages/JVM/index.js Dosyayı Görüntüle

@@ -11,7 +11,7 @@ import {
Button
} from '@mui/material';
import * as React from "react";
import { GET_JVM_INFO } from "utils/ApiPathConst";
import { GET_JVM_INFO, GET_NOTIFICATION_QUEUE_STATUS } from "utils/ApiPathConst";
import axios from "axios";

import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
@@ -20,7 +20,11 @@ const JVMDefault = () => {
const [jvmInfo, setJvmInfo] = React.useState(null);
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState(null);

const [queueStatus, setQueueStatus] = React.useState(null);
const [queueLoading, setQueueLoading] = React.useState(false);
const [queueError, setQueueError] = React.useState(null);

const fetchJvmInfo = () => {
setLoading(true);
setError(null);
@@ -37,6 +41,24 @@ const JVMDefault = () => {
});
};

const fetchNotificationQueueStatus = () => {
setQueueLoading(true);
setQueueError(null);
setQueueStatus(null);
axios.get(`${GET_NOTIFICATION_QUEUE_STATUS}`)
.then((response) => {
if (response.status === 200) {
setQueueStatus(response.data);
}
})
.catch(err => {
setQueueError(err);
})
.finally(() => {
setQueueLoading(false);
});
};

React.useEffect(() => {
localStorage.setItem('searchCriteria', "");
setLoading(false);
@@ -66,25 +88,40 @@ const JVMDefault = () => {
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="space-between" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{ "textShadow": "0px 0px 25px #0C489E" }}>
JVM Information
System Background Status
</Typography>
</Stack>
</div>
</Grid>
<Grid item xs={12} ml={15} mb={2} mt={2}>
<Button
size="large"
variant="contained"
type="submit"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
onClick={fetchJvmInfo}
disabled={loading}
>
<Typography variant="h5">JVM Info</Typography>
</Button>
<Stack direction="row" spacing={2}>
<Button
size="large"
variant="contained"
type="submit"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
onClick={fetchJvmInfo}
disabled={loading}
>
<Typography variant="h5">JVM Info</Typography>
</Button>
<Button
size="large"
variant="contained"
type="button"
sx={{
textTransform: 'capitalize',
alignItems: 'end'
}}
onClick={fetchNotificationQueueStatus}
disabled={queueLoading}
>
<Typography variant="h5">Notification Queue Status</Typography>
</Button>
</Stack>
</Grid>
<Grid item xs={12} ml={15} mb={2} mt={2}>
<Paper elevation={3} sx={{ p: 2, bgcolor: 'background.paper' }}>
@@ -114,6 +151,35 @@ const JVMDefault = () => {
)}
</Paper>
</Grid>
<Grid item xs={12} ml={15} mb={2} mt={2}>
<Paper elevation={3} sx={{ p: 2, bgcolor: 'background.paper' }}>
<Typography variant="h6" gutterBottom>Notification Queue Status</Typography>
{queueLoading ? (
<Box display="flex" justifyContent="center" alignItems="center" minHeight={120}>
<CircularProgress />
</Box>
) : queueError ? (
<Typography color="error">Error: {queueError.message}</Typography>
) : queueStatus ? (
<Box
component="pre"
sx={{
p: 2,
borderRadius: 1,
bgcolor: 'grey.100',
overflow: 'auto',
maxHeight: 300,
fontSize: '0.875rem',
lineHeight: 1.6
}}
>
{JSON.stringify(queueStatus, null, 2)}
</Box>
) : (
<Typography color="text.secondary">Click &quot;Notification Queue Status&quot; to load data.</Typography>
)}
</Paper>
</Grid>
</Grid>
);
};


+ 7
- 3
src/pages/Message/Details/index.js Dosyayı Görüntüle

@@ -17,6 +17,8 @@ const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/Loa

import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
import { FormattedMessage } from "react-intl";
import usePageTitle from 'components/usePageTitle';

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
width: '100%',
@@ -30,6 +32,8 @@ const BackgroundHead = {
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const Index = () => {
usePageTitle("msgDetails");
const params = useParams();
const navigate = useNavigate()

@@ -72,7 +76,7 @@ const Index = () => {
<Grid item xs={12} width="100%">
<div style={BackgroundHead} width="100%">
<Stack direction="row" height='70px'>
<Typography ml={15} color='#FFF' variant="h4" sx={{ pt: 2 }}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{ pt: 2 }}>
<FormattedMessage id="msgDetails" />
</Typography>
</Stack>
@@ -83,7 +87,7 @@ const Index = () => {
<Grid container justifyContent="flex-start" alignItems="center" >
<center>
<Grid item xs={12} md={12} sx={{p:2}} >
<Typography variant="h3" sx={{ textAlign: "left", borderBottom: "1px solid black" }}>
<Typography component="h2" variant="h3" sx={{ textAlign: "left", borderBottom: "1px solid black" }}>
{record?.subject}
</Typography>
<Typography sx={{p:1}} align="justify">{DateUtils.datetimeStr(record?.sentDate)}</Typography>
@@ -91,7 +95,7 @@ const Index = () => {
<div dangerouslySetInnerHTML={{__html: record?.content}}></div>
</Typography>

<Typography variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "center" }}>
<Typography component="h3" variant="h4" sx={{ ml: 8, mt: 4, mr: 8, textAlign: "center" }}>
<Button
component="span"
variant="contained"


+ 2
- 2
src/pages/Message/Search/SearchForm.js Dosyayı Görüntüle

@@ -119,7 +119,7 @@ const SearchForm = ({ applySearch, searchCriteria, onGridReady }) => {
<Grid item xs={12} s={6} md={6} lg={4} sx={{ ml: 3, mr: 3, mb: 3 }}>
<Grid container>
<Grid item xs={5.25} s={5.25} md={5.25} lg={5.5}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateFrom"
@@ -151,7 +151,7 @@ const SearchForm = ({ applySearch, searchCriteria, onGridReady }) => {
</Grid>

<Grid item xs={5.25} s={5.25} md={5.25} lg={5.5}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateTo"


+ 3
- 2
src/pages/Message/Search/index.js Dosyayı Görüntüle

@@ -17,7 +17,7 @@ const EventTable = Loadable(React.lazy(() => import('./DataGrid')));
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
import {FormattedMessage} from "react-intl";
import { getSearchCriteria } from "auth/utils";
import usePageTitle from "components/usePageTitle";
const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
width: '100%',
@@ -31,6 +31,7 @@ const BackgroundHead = {
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const Index = () => {
usePageTitle("systemMessage");

const [searchCriteria, setSearchCriteria] = React.useState({});
const [onReady, setOnReady] = React.useState(false);
@@ -87,7 +88,7 @@ const Index = () => {
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
<FormattedMessage id="systemMessage"/>
</Typography>
</Stack>


+ 57
- 51
src/pages/Organization/DetailPage/OrganizationCard.js Dosyayı Görüntüle

@@ -2,7 +2,7 @@
import {
Grid, Button, Checkbox, FormControlLabel, Typography,
Dialog, DialogTitle, DialogContent, DialogActions,
FormHelperText, TextField,
FormHelperText, TextField, CircularProgress,
} from '@mui/material';
// import { FormControlLabel } from '@material-ui/core';
import MainCard from "components/MainCard";
@@ -111,56 +111,58 @@ const OrganizationCard = ({ userData, loadDataFun, id, setEditModeFun }) => {
onSubmit: (values) => {
if (values.country == null) {
setErrorMsg(intl.formatMessage({ id: 'pleaseFillInCountry' }))
} else {
if (values.country.type == "hongKong" && values.district == null) {
setErrorMsg(intl.formatMessage({ id: 'pleaseFillInDistrict' }))
} else {
let sentDateFrom = "";
if (fromDateValue == null) {
setErrorMsg(intl.formatMessage({ id: 'pleaseFillInBusinessRegCertValidityDate' }))
} else {
sentDateFrom = DateUtils.dateValue(fromDateValue)
HttpUtils.post({
url: UrlUtils.POST_ORG_SAVE_PATH,
params: {
id: id > 0 ? id : null,
enCompanyName: values.enCompanyName,
chCompanyName: values.chCompanyName,
orgShortName: values.orgShortName === "N/A" ? "" : values.orgShortName,
brNo: values.brNo,
// brExpiryDate: values.brExpiryDate,
brExpiryDate: sentDateFrom,
enCompanyNameTemp: values.enCompanyNameTemp,
chCompanyNameTemp: values.chCompanyNameTemp,
brExpiryDateTemp: values.brExpiryDateTemp,
contactPerson: values.contactPerson,
contactTel: {
countryCode: values.tel_countryCode,
phoneNumber: values.phoneNumber
},
faxNo: {
countryCode: values.fax_countryCode,
faxNumber: values.faxNumber
},
addressTemp: {
country: values.country.type,
district: values.district?.type,
addressLine1: values.addressLine1,
addressLine2: values.addressLine2,
addressLine3: values.addressLine3,
},
creditor: values.creditor,
},
onSuccess: function () {
notifySaveSuccess()
loadDataFun();
setEditMode(false);
}
});
}

}
return;
}
if (values.country.type == "hongKong" && values.district == null) {
setErrorMsg(intl.formatMessage({ id: 'pleaseFillInDistrict' }))
return;
}
if (fromDateValue == null) {
setErrorMsg(intl.formatMessage({ id: 'pleaseFillInBusinessRegCertValidityDate' }))
return;
}
const sentDateFrom = DateUtils.dateValue(fromDateValue);
return new Promise((resolve, reject) => {
HttpUtils.post({
url: UrlUtils.POST_ORG_SAVE_PATH,
params: {
id: id > 0 ? id : null,
enCompanyName: values.enCompanyName,
chCompanyName: values.chCompanyName,
orgShortName: values.orgShortName === "N/A" ? "" : values.orgShortName,
brNo: values.brNo,
brExpiryDate: sentDateFrom,
enCompanyNameTemp: values.enCompanyNameTemp,
chCompanyNameTemp: values.chCompanyNameTemp,
brExpiryDateTemp: values.brExpiryDateTemp,
contactPerson: values.contactPerson,
contactTel: {
countryCode: values.tel_countryCode,
phoneNumber: values.phoneNumber
},
faxNo: {
countryCode: values.fax_countryCode,
faxNumber: values.faxNumber
},
addressTemp: {
country: values.country.type,
district: values.district?.type,
addressLine1: values.addressLine1,
addressLine2: values.addressLine2,
addressLine3: values.addressLine3,
},
creditor: values.creditor,
},
onSuccess: function () {
notifySaveSuccess()
loadDataFun();
setEditMode(false);
resolve();
},
onFail: () => reject(),
onError: () => reject(),
});
});
}
});

@@ -267,6 +269,8 @@ const OrganizationCard = ({ userData, loadDataFun, id, setEditModeFun }) => {
variant="contained"
type="submit"
color="success"
disabled={formik.isSubmitting}
startIcon={formik.isSubmitting ? <CircularProgress color="inherit" size={18} /> : null}
>
Create
</Button>
@@ -289,6 +293,8 @@ const OrganizationCard = ({ userData, loadDataFun, id, setEditModeFun }) => {
variant="contained"
type="submit"
color="success"
disabled={formik.isSubmitting}
startIcon={formik.isSubmitting ? <CircularProgress color="inherit" size={18} /> : null}
>
Save
</Button>
@@ -440,7 +446,7 @@ const OrganizationCard = ({ userData, loadDataFun, id, setEditModeFun }) => {
value={fromDate != null ? DateUtils.dateStr(fromDate) : DateUtils.dateStr(currentFromDate)}
disabled={true}
/> :
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="brExpiryDate"


+ 42
- 34
src/pages/Organization/DetailPage/OrganizationPubCard.js Dosyayı Görüntüle

@@ -4,7 +4,7 @@ import {
// Checkbox, FormControlLabel,
Typography,
Dialog, DialogTitle, DialogContent, DialogActions,
FormHelperText
FormHelperText, CircularProgress,
} from '@mui/material';
// import { FormControlLabel } from '@material-ui/core';
import MainCard from "components/MainCard";
@@ -61,42 +61,46 @@ const OrganizationPubCard = ({ userData, loadDataFun, id, setEditModeFun }) => {
phoneNumber: yup.string().min(8, displayErrorMsg(intl.formatMessage({ id: 'requiredValidNumber' }))).required(displayErrorMsg(intl.formatMessage({ id: 'requireContactNumber' }))),
faxNumber: yup.string().min(8, displayErrorMsg(intl.formatMessage({ id: 'require8Number' }))).nullable(),
}),
onSubmit: values => {
onSubmit: (values) => {
if (values.country == null) {
setErrorMsg(intl.formatMessage({ id: 'pleaseFillInCountry' }))
} else {
if (values.country.type == "hongKong" && values.district == null) {
setErrorMsg(intl.formatMessage({ id: 'pleaseFillInDistrict' }))
} else {
HttpUtils.post({
url: UrlUtils.POST_PUB_ORG_SAVE_PATH,
params: {
contactPerson: values.contactPerson,
contactTel: {
countryCode: values.tel_countryCode,
phoneNumber: values.phoneNumber
},
faxNo: {
countryCode: values.fax_countryCode,
faxNumber: values.faxNumber
},
addressTemp: {
country: values.country.type,
district: values.district?.type,
addressLine1: values.addressLine1,
addressLine2: values.addressLine2,
addressLine3: values.addressLine3,
},
//creditor: values.creditor,
},
onSuccess: function () {
notifySaveSuccess()
loadDataFun();
setEditMode(false);
}
});
}
return;
}
if (values.country.type == "hongKong" && values.district == null) {
setErrorMsg(intl.formatMessage({ id: 'pleaseFillInDistrict' }))
return;
}
return new Promise((resolve, reject) => {
HttpUtils.post({
url: UrlUtils.POST_PUB_ORG_SAVE_PATH,
params: {
contactPerson: values.contactPerson,
contactTel: {
countryCode: values.tel_countryCode,
phoneNumber: values.phoneNumber
},
faxNo: {
countryCode: values.fax_countryCode,
faxNumber: values.faxNumber
},
addressTemp: {
country: values.country.type,
district: values.district?.type,
addressLine1: values.addressLine1,
addressLine2: values.addressLine2,
addressLine3: values.addressLine3,
},
},
onSuccess: function () {
notifySaveSuccess()
loadDataFun();
setEditMode(false);
resolve();
},
onFail: () => reject(),
onError: () => reject(),
});
});
}
});

@@ -147,6 +151,8 @@ const OrganizationPubCard = ({ userData, loadDataFun, id, setEditModeFun }) => {
variant="contained"
type="submit"
color="success"
disabled={formik.isSubmitting}
startIcon={formik.isSubmitting ? <CircularProgress color="inherit" size={18} /> : null}
>
<FormattedMessage id="create" />
</Button>
@@ -171,6 +177,8 @@ const OrganizationPubCard = ({ userData, loadDataFun, id, setEditModeFun }) => {
variant="contained"
type="submit"
color="success"
disabled={formik.isSubmitting}
startIcon={formik.isSubmitting ? <CircularProgress color="inherit" size={18} /> : null}
>
<FormattedMessage id="save" />
</Button>


+ 6
- 2
src/pages/Organization/DetailPage/index.js Dosyayı Görüntüle

@@ -22,6 +22,7 @@ import {
isORGLoggedIn,
isPrimaryLoggedIn
} from "utils/Utils";
import usePageTitle from "components/usePageTitle";

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
@@ -42,6 +43,9 @@ import {


const OrganizationDetailPage = () => {
// Localized document title/meta for organisation details (GLD)
usePageTitle("organizationProfile");

const params = useParams();
const [formData, setFormData] = React.useState({})
const [list, setList] = React.useState([])
@@ -136,11 +140,11 @@ const OrganizationDetailPage = () => {
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
{isGLDLoggedIn()?
<Typography ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
Maintain Organisation
</Typography>
:
<Typography ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
<FormattedMessage id="organizationProfile" />
</Typography>
}


+ 1
- 1
src/pages/Organization/DetailPage_FromUser/OrganizationCard_loadFromUser.js Dosyayı Görüntüle

@@ -233,7 +233,7 @@ const OrganizationCard_loadFromUser = ({ userData, userId }) => {
<Typography variant="pnspsFormParagraphBold">{FieldUtils.notNullFieldLabel("Expiry Date:")}</Typography>
</Grid>
<Grid item xs={12} md={6} lg={6}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="brExpiryDate"


+ 4
- 0
src/pages/Organization/DetailPage_FromUser/index.js Dosyayı Görüntüle

@@ -25,10 +25,14 @@ const BackgroundHead = {
backgroundColor: '#0C489E',
backgroundPosition: 'right'
}
import usePageTitle from "components/usePageTitle";
// ==============================|| DASHBOARD - DEFAULT ||============================== //


const OrganizationDetailPage_FromUser = () => {
// Localized document title/meta for organisation details (from user)
usePageTitle("organizationProfile");

const params = useParams();
const [formData, setFormData] = useState({})
const [isLoading, setLoding] = useState(true);


+ 1
- 1
src/pages/Organization/SearchPage/OrganizationSearchForm.js Dosyayı Görüntüle

@@ -154,7 +154,7 @@ const OrganizationSearchForm = ({ applySearch, onGridReady, searchCriteria }) =>
'& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
'& .MuiOutlinedInput-root': { height: 40 }
}}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
renderInput={(params) => (
<TextField
{...params}


+ 3
- 0
src/pages/Organization/SearchPage/index.js Dosyayı Görüntüle

@@ -6,6 +6,7 @@ import MainCard from "components/MainCard";
import { useEffect, useState } from "react";
import * as React from "react";
import { getSearchCriteria } from "auth/utils";
import usePageTitle from "components/usePageTitle";

// import LoadingComponent from "../extra-pages/LoadingComponent";
// import SearchForm from "./OrganizationSearchForm";
@@ -29,6 +30,8 @@ const BackgroundHead = {
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const OrganizationSearchPage = () => {
// Localized document title/meta for organisation search
usePageTitle("organizationProfile");

const [searchCriteria, setSearchCriteria] = useState({});
const [onReady, setOnReady] = useState(false);


+ 5
- 2
src/pages/Payment/Details_Public/index.js Dosyayı Görüntüle

@@ -20,6 +20,7 @@ const DataGrid = Loadable(React.lazy(() => import('./DataGrid')));
import ForwardIcon from '@mui/icons-material/Forward';
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
import {FormattedMessage,useIntl} from "react-intl";
import usePageTitle from "components/usePageTitle";
const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
width: '100%',
@@ -33,6 +34,8 @@ const BackgroundHead = {
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const Index = () => {
usePageTitle("payDetail");
const params = useParams();
const navigate = useNavigate()
const intl = useIntl();
@@ -144,7 +147,7 @@ const Index = () => {
<Grid className="printHidden" item xs={12} width="100%">
<div style={BackgroundHead} width="100%">
<Stack direction="row" height='70px'>
<Typography ml={15} color='#FFF' variant="h4" sx={{ pt: 2 }}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{ pt: 2 }}>
<FormattedMessage id="payDetail"/>
</Typography>
</Stack>
@@ -160,7 +163,7 @@ const Index = () => {
</Button>
</Grid>
{/*row 1*/}
<Grid item xs={12} md={12} spacing={2} sx={{ textAlign: "center" }}>
<Grid item xs={12} md={12} sx={{ textAlign: "center" }}>
<Grid container justifyContent="center" direction="column" spacing={2} sx={{ p: 2 }} alignitems="stretch" >
<Grid item className="printOrder" xs={12} md={12} sx={{ pt: 2 }} style={{ height: '100%', order: 1 }}>
<Box xs={12} md={12} sx={{ border: '3px solid #eee', borderRadius: '10px' }} >


+ 4
- 8
src/pages/Payment/Search_GLD/SearchForm.js Dosyayı Görüntüle

@@ -222,7 +222,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
filterOptions={(options) => options}
options={ComboData.paymentStatus}
value={status}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
inputValue={status?.label ? status?.label : ""}
onChange={(event, newValue) => {
if(newValue==null){
@@ -239,11 +239,9 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
renderInput={(params) => (
<TextField {...params}
label="Status"
InputLabelProps={{ shrink: true }}
/>
)}
InputLabelProps={{
shrink: true
}}
/>
</Grid>
@@ -256,7 +254,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
filterOptions={(options) => options}
options={ComboData.payMethod}
value={payMethod}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
inputValue={payMethod?.label ? payMethod?.label : ""}
onChange={(event, newValue) => {
if(newValue==null){
@@ -273,11 +271,9 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
renderInput={(params) => (
<TextField {...params}
label="Payment Method"
InputLabelProps={{ shrink: true }}
/>
)}
InputLabelProps={{
shrink: true
}}
/>
</Grid>
</Grid>


+ 9
- 6
src/pages/Payment/Search_Public/SearchForm.js Dosyayı Görüntüle

@@ -124,7 +124,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
<Grid item xs={12} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<Grid container spacing={1}>
<Grid item xs={6}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateFrom"
@@ -152,7 +152,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
</Grid>

<Grid item xs={6}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateTo"
@@ -206,13 +206,16 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
'& .MuiOutlinedInput-root': { height: 40 }
}}
renderInput={(params) => (
<TextField {...params}
<TextField
{...params}
label={intl.formatMessage({id: 'status'})}
InputLabelProps={{ ...params.InputLabelProps, shrink: true }}
/>
)}
InputLabelProps={{
shrink: true
}}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
/>
</Grid>



+ 3
- 1
src/pages/Payment/Search_Public/index.js Dosyayı Görüntüle

@@ -15,6 +15,7 @@ const EventTable = Loadable(React.lazy(() => import('./DataGrid')));
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
import {FormattedMessage} from "react-intl";
import { getSearchCriteria } from "auth/utils";
import usePageTitle from "components/usePageTitle";

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
@@ -29,6 +30,7 @@ const BackgroundHead = {
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const Index = () => {
usePageTitle("onlinePaymentHistory");
const [searchCriteria, setSearchCriteria] = React.useState({
dateTo: DateUtils.dateValue(new Date()),
dateFrom: DateUtils.dateValue(new Date().setDate(new Date().getDate()-14)),
@@ -76,7 +78,7 @@ const Index = () => {
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
<FormattedMessage id="onlinePaymentHistory"/>
</Typography>
</Stack>


+ 49
- 12
src/pages/Proof/Create_FromApp/ProofForm.js Dosyayı Görüntüle

@@ -19,12 +19,23 @@ import * as ComboData from "utils/ComboData";
import * as React from "react";
import { useFormik } from 'formik';
import { useNavigate } from "react-router-dom";
import { useIntl } from 'react-intl';
import Loadable from 'components/Loadable';
import { notifySaveSuccess } from 'utils/CommonFunction';
const UploadFileTable = Loadable(React.lazy(() => import('./UploadFileTable')));

const FormPanel = ({ formData }) => {
/** Keeps Formik fields defined so inputs stay controlled before API data loads. */
const proofFormInitialValues = {
reviseDeadline: '',
proofPaymentDeadline: '',
length: 0,
noOfPages: 0,
fee: 0,
groupType: ''
};

const FormPanel = ({ formData }) => {
const intl = useIntl();
const [data, setData] = React.useState({});
const [columnPrice, setColumnPrice] = React.useState(ComboData.proofPrice[0]);
const [attachments, setAttachments] = React.useState([]);
@@ -41,16 +52,24 @@ const FormPanel = ({ formData }) => {

const [proofPaymentDeadlineMin, setProofPaymentDeadlineMin] = React.useState({});
const [reviseDeadlineMin, setReviseDeadlineMin] = React.useState({});
const fileInputRef = React.useRef(null);

const navigate = useNavigate()

React.useEffect(() => {
if (formData) {
setData(formData);
const normalizedFormData = {
...formData,
length: formData.length ?? 0,
noOfPages: formData.noOfPages ?? 0,
fee: formData.fee ?? 0
};

if (formData.groupType == "Private Bill") {
setColumnPrice(ComboData.proofPrice[1])
formData['length'] = 18;
normalizedFormData['length'] = 18;
}
setData(normalizedFormData);
setProofPaymentDeadlineMin(formData.proofPaymentDeadline);
setReviseDeadlineMin(formData.reviseDeadline);
setExpectedCode(formData.groupNo.substr(1,formData.groupNo.length)+"-"+formData.issueNo+"-"+formData.issueYear.toString().substr(2, formData.issueYear.toString().length));
@@ -121,7 +140,7 @@ const FormPanel = ({ formData }) => {

const formik = useFormik({
enableReinitialize: true,
initialValues: data,
initialValues: { ...proofFormInitialValues, ...data },
onSubmit: values => {
setSaving(true);
if (!attachments || attachments.length <= 0) {
@@ -167,7 +186,9 @@ const FormPanel = ({ formData }) => {
if (msg === "haveActiveProof") {
msg = "Action Failed: There is already a pending payment and proofreading record for client review."
} else if (msg === "haveProofed") {
msg = "Action Failed: Already proofed."
msg = "Action Failed: An active proof is already created for this application."
} else {
msg = intl.formatMessage({ id: msg });
}
setWarningText(msg);
setIsWarningPopUp(true);
@@ -203,7 +224,7 @@ const FormPanel = ({ formData }) => {
}

return (
<MainCard xs={12} md={12} lg={12}
<MainCard
border={false}
content={false}>

@@ -275,12 +296,26 @@ const FormPanel = ({ formData }) => {
</Grid>
<Grid item xs={12} md={12}>
<Button
component="label"
variant="contained"
size="large"
disabled={attachments.length >= (formik.values.groupType == "Private Bill" ? 2 : 1)}
type="button"
onClick={() => {
if (fileInputRef.current) {
fileInputRef.current.click();
}
}}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
if (fileInputRef.current) {
fileInputRef.current.click();
}
}
}}
>
<Typography variant="h5">Upload Files</Typography>
<Typography variant="h5">Upload Files</Typography>
</Button>
<input
id="uploadFileBtn"
name="file"
@@ -289,9 +324,9 @@ const FormPanel = ({ formData }) => {
hidden
disabled={attachments.length >= (formik.values.groupType == "Private Bill" ? 2 : 1)}
onChange={readFile}
aria-label="Upload PDF file"
aria-label={intl.formatMessage({ id: 'ariaUploadPdfFile' })}
ref={fileInputRef}
/>
</Button>
</Grid>
<Grid item xs={12} md={12}>
<UploadFileTable
@@ -407,7 +442,9 @@ const FormPanel = ({ formData }) => {
options={ComboData.proofPrice}
value={columnPrice}
inputValue={(columnPrice?.label) ? columnPrice?.label : ""}
getOptionLabel={(option) => option.label ? option.label : ""}
getOptionLabel={(option) =>
option != null && option.label != null ? String(option.label) : ""
}
onChange={(event, newValue) => {
setColumnPrice(newValue)
formik.values["fee"] = newValue.value * formik.values.length;
@@ -494,7 +531,7 @@ const FormPanel = ({ formData }) => {
}
}}
>
<DialogTitle><Typography variant="h3">Warning</Typography></DialogTitle>
<DialogTitle><Typography component="span" variant="h3">Warning</Typography></DialogTitle>
<DialogContent style={{ display: 'flex', }}>
<Typography variant="h4" style={{ padding: '16px' }}>{warningText}</Typography>
</DialogContent>


+ 3
- 3
src/pages/Proof/Create_FromApp/index.js Dosyayı Görüntüle

@@ -75,7 +75,7 @@ const Index = () => {
</Grid>
</Grid>
:
<Grid container sx={{ minHeight: '85vh', backgroundColor: "backgroundColor.default" }} direction="column" spacing={1} >
<Grid container sx={{ minHeight: '85vh', bgcolor: 'background.default' }} direction="column" spacing={1} >
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
@@ -88,7 +88,7 @@ const Index = () => {
border={false}
content={false}
sx={{
backgroundColor: "backgroundColor.default"
bgcolor: 'background.default'
}}
>

@@ -126,7 +126,7 @@ const Index = () => {
<MainCard elevation={0}
border={false}
content={false}
backgroundColor={"backgroundColor.default"}
sx={{ bgcolor: 'background.default' }}
>
<Box xs={12} ml={4} mt={3} sx={{ p: 1, borderRadius: '10px', backgroundColor: "#fff" }}>
<ProofForm


+ 52
- 8
src/pages/Proof/Reply_GLD/ApplicationDetails.js Dosyayı Görüntüle

@@ -8,11 +8,13 @@ import {
Button,
Stack,
Dialog, DialogTitle, DialogContent, DialogActions,
CircularProgress,
} from '@mui/material';

import { useFormik } from 'formik';
import { useIntl } from 'react-intl';
import {isGranted} from "auth/utils";
import {useState,useEffect,lazy} from "react";
import {useState, useEffect, useRef, lazy} from "react";
import * as HttpUtils from "utils/HttpUtils"
import * as UrlUtils from "utils/ApiPathConst"
import * as DateUtils from "utils/DateUtils"
@@ -31,10 +33,15 @@ const ApplicationDetailCard = ({
}) => {

const params = useParams();
const intl = useIntl();

const [data, setData] = useState({});
const [cancelPopUp, setCancelPopUp] = useState(false);
const [cancelLoading, setCancelLoading] = useState(false);
const cancellingRef = useRef(false);
const [onDownload, setOnDownload] = useState(false);
const [alertMsg, setAlertMsg] = useState('');
const [showAlert, setShowAlert] = useState(false);

useEffect(() => {
if (formData) {
@@ -94,11 +101,30 @@ const ApplicationDetailCard = ({
}

const confirmCancel = () => {
setCancelPopUp(false);
if (cancellingRef.current) return;
cancellingRef.current = true;
setCancelLoading(true);
HttpUtils.get({
url: UrlUtils.CANCEL_PROOF + "/" + params.id,
onSuccess: function () {
window.location.reload(false);
onSuccess: function (responseData) {
cancellingRef.current = false;
setCancelLoading(false);
if (responseData && responseData.success === false) {
setCancelPopUp(false);
const msg = responseData.msg ? intl.formatMessage({ id: responseData.msg }) : intl.formatMessage({ id: 'proofAlreadyCancelled' });
setAlertMsg(msg);
setShowAlert(true);
} else {
window.location.reload(false);
}
},
onFail: () => {
cancellingRef.current = false;
setCancelLoading(false);
},
onError: () => {
cancellingRef.current = false;
setCancelLoading(false);
}
});
}
@@ -189,7 +215,7 @@ const ApplicationDetailCard = ({

<Grid item xs={12} md={9} lg={9} sx={{ display: 'flex', alignItems: 'center' }}>
<FormControl variant="outlined">
{StatusUtils.getStatusByText(data.appStatus)}
{StatusUtils.getStatusByTextEng(data.appStatus, data.creditor)}
</FormControl>
</Grid>
</Grid>
@@ -338,15 +364,33 @@ const ApplicationDetailCard = ({
<div>
<Dialog
open={cancelPopUp}
onClose={() => setCancelPopUp(false)}
onClose={() => {
if (cancelLoading) return;
setCancelPopUp(false);
}}
>
<DialogTitle><Typography variant="h3">Confirm</Typography></DialogTitle>
<DialogContent style={{ display: 'flex', }}>
<Typography variant="h4" style={{ padding: '16px' }}>Are you sure you want to cancel this proof?</Typography>
</DialogContent>
<DialogActions>
<Button onClick={() => setCancelPopUp(false)}><Typography variant="h5">Cancel</Typography></Button>
<Button onClick={() => confirmCancel()}><Typography variant="h5">Confirm</Typography></Button>
<Button onClick={() => setCancelPopUp(false)} disabled={cancelLoading}><Typography variant="h5">Cancel</Typography></Button>
<Button
onClick={() => confirmCancel()}
disabled={cancelLoading}
startIcon={cancelLoading ? <CircularProgress color="inherit" size={20} /> : null}
>
<Typography variant="h5">Confirm</Typography>
</Button>
</DialogActions>
</Dialog>
<Dialog open={showAlert} onClose={() => setShowAlert(false)}>
<DialogTitle><Typography variant="h3">{intl.formatMessage({ id: 'attention' })}</Typography></DialogTitle>
<DialogContent>
<Typography variant="h4" style={{ padding: '16px' }}>{alertMsg}</Typography>
</DialogContent>
<DialogActions>
<Button onClick={() => setShowAlert(false)}><Typography variant="h5">OK</Typography></Button>
</DialogActions>
</Dialog>
</div>


+ 36
- 18
src/pages/Proof/Reply_Public/ProofForm.js Dosyayı Görüntüle

@@ -55,6 +55,7 @@ const FormPanel = ({ formData }) => {
const [isSubmitting, setIsSubmitting] = React.useState(false);
const [isOnlyOnlinePayment, setOnlyOnlinePayment] = React.useState();
const [isNoPayment, setNoPayment] = React.useState();
const fileInputRef = React.useRef(null);
const navigate = useNavigate()
const params = useParams();
@@ -166,14 +167,16 @@ const FormPanel = ({ formData }) => {
onFail: function (response) {
setIsSubmitting(false);
setWarningTitle(intl.formatMessage({ id: "attention" }))
setWarningText(intl.formatMessage({ id: 'actionFail' }));
const msg = response?.data?.msg ? intl.formatMessage({ id: response.data.msg }) : intl.formatMessage({ id: 'actionFail' });
setWarningText(msg);
setIsWarningPopUp(true);
console.log(response);
},
onError: function (error) {
setIsSubmitting(false);
setWarningTitle(intl.formatMessage({ id: "attention" }))
setWarningText(intl.formatMessage({ id: 'actionFail' }));
const msg = error?.response?.data?.msg ? intl.formatMessage({ id: error.response.data.msg }) : intl.formatMessage({ id: 'actionFail' });
setWarningText(msg);
setIsWarningPopUp(true);
console.log(error);
}
@@ -628,6 +631,30 @@ const FormPanel = ({ formData }) => {
</Grid>

<Grid item xs={12} md={12} textAlign="left">
<ThemeProvider theme={PNSPS_BUTTON_THEME}>
<Button
color="save"
variant="contained"
type="button"
aria-label={intl.formatMessage({ id: 'upload' })}
disabled={attachments.length >= (formik.values.groupType === "Private Bill" ? 2 : 1)}
onClick={() => {
if (fileInputRef.current) {
fileInputRef.current.click();
}
}}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
if (fileInputRef.current) {
fileInputRef.current.click();
}
}
}}
>
<FormattedMessage id="upload" />
</Button>
</ThemeProvider>
<input
id="uploadFileBtn"
name="file"
@@ -638,20 +665,8 @@ const FormPanel = ({ formData }) => {
onChange={(event) => {
readFile(event)
}}
ref={fileInputRef}
/>
<label htmlFor="uploadFileBtn">
<ThemeProvider theme={PNSPS_BUTTON_THEME}>
<Button
color="save"
component="span"
variant="contained"
aria-label={intl.formatMessage({ id: 'upload' })}
disabled={attachments.length >= (formik.values.groupType === "Private Bill" ? 2 : 1)}
>
<FormattedMessage id="upload" />
</Button>
</ThemeProvider>
</label>
</Grid>


@@ -700,13 +715,16 @@ const FormPanel = ({ formData }) => {
<ThemeProvider theme={PNSPS_BUTTON_THEME}>
<Button
variant="contained"
color="success"
type="submit"
disabled={(actionValue == false && isOverReviseDeadline()) || isSubmitting}
startIcon={isSubmitting ? <CircularProgress size={20} color="inherit" /> : null}
aria-label={intl.formatMessage({ id: 'submitReply' })}
sx={{
backgroundColor: '#0C489E',
color: '#FFFFFF',
'&:hover': { backgroundColor: '#093A7A' },
}}
>
<FormattedMessage id="submitReply" />
{isSubmitting ? <FormattedMessage id="loading" /> : <FormattedMessage id="submitReply" />}
</Button>
</ThemeProvider>
</Grid>


+ 7
- 9
src/pages/Proof/Reply_Public/index.js Dosyayı Görüntüle

@@ -21,6 +21,7 @@ const ProofForm = Loadable(React.lazy(() => import('./ProofForm')));
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
import MainCard from "../../../components/MainCard";
import {FormattedMessage} from "react-intl";
import usePageTitle from "components/usePageTitle";
const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
width: '100%',
@@ -35,6 +36,8 @@ import {useIntl} from "react-intl";
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const Index = () => {
usePageTitle("proofRecord");
const params = useParams();
const navigate = useNavigate()
const intl = useIntl();
@@ -92,7 +95,7 @@ const Index = () => {
<Grid item xs={12} width="100%">
<div style={BackgroundHead} width="100%">
<Stack direction="row" height='70px'>
<Typography ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }, pt:2}}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }, pt:2}}>
<FormattedMessage id="proofRecord"/>
</Typography>
</Stack>
@@ -111,12 +114,10 @@ const Index = () => {
<Grid item xs={12} sm={12} md={12} lg={12} sx={{ width:'100%', mt:2, mb: -3}}>
<MainCard
sx={{
mr:2,
mr: 2,
boxShadow: 1,
border: 1,
borderColor: '#DDD',
border: '1px groove #DDD',
}}
border= '1px groove grey'
>
<ApplicationDetails
formData={record}
@@ -129,11 +130,8 @@ const Index = () => {
<MainCard
sx={{
boxShadow: 1,
border: 1,
borderColor: '#DDD',
border: '1px groove #DDD',
}}
border= '1px groove grey'
// sx={..._sx}
>
<ProofForm
formData={record}


+ 5
- 1
src/pages/Proof/Search_GLD/DataGrid.js Dosyayı Görüntüle

@@ -46,10 +46,14 @@ export default function SearchPublicNoticeTable({searchCriteria, applyGridOnRead
},
},
{
id: 'actions',
id: 'proofStatus',
field: 'proofStatus',
headerName: 'Status',
flex: 1,
minWidth: 150,
sortable: false,
filterable: false,
valueGetter: () => '',
renderCell: (params) => {
return ProofStatus.getStatus_Eng(params);
},


+ 15
- 16
src/pages/Proof/Search_GLD/SearchForm.js Dosyayı Görüntüle

@@ -26,11 +26,15 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss

const [type, setType] = React.useState([]);
const [status, setStatus] = React.useState(searchCriteria.statusKey!=undefined?ComboData.proofStatus_GLD[searchCriteria.statusKey]:ComboData.proofStatus_GLD[0]);
const [orgSelected, setOrgSelected] = React.useState({});
const [orgSelected, setOrgSelected] = React.useState(null);
const [orgCombo, setOrgCombo] = React.useState();
const [issueSelected, setIssueSelected] = React.useState({});
const [issueSelected, setIssueSelected] = React.useState(null);
const [issueCombo, setIssueCombo] = React.useState([]);
const [groupSelected, setGroupSelected] = React.useState(searchCriteria.gazettGroup!=undefined?ComboData.groupTitle.find(item => item.code === searchCriteria.gazettGroup):{});
const [groupSelected, setGroupSelected] = React.useState(
searchCriteria.gazettGroup != undefined
? ComboData.groupTitle.find(item => item.code === searchCriteria.gazettGroup) ?? null
: null
);

const [minDate, setMinDate] = React.useState(searchCriteria.dateFrom);
const [maxDate, setMaxDate] = React.useState(searchCriteria.dateTo);
@@ -136,9 +140,9 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss
function resetForm() {
setType([]);
setStatus(ComboData.proofStatus[0]);
setOrgSelected({});
setIssueSelected({});
setGroupSelected({});
setOrgSelected(null);
setIssueSelected(null);
setGroupSelected(null);
setMinDate(DateUtils.dateValue(new Date().setDate(new Date().getDate()-14)))
setMaxDate(DateUtils.dateValue(new Date()))
reset({
@@ -257,7 +261,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss
options={ComboData.groupTitle}
value={groupSelected}
inputValue={(groupSelected?.label) ? groupSelected?.label : ""}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
onChange={(event, newValue) => {
setGroupSelected(newValue);
}}
@@ -371,13 +375,12 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss
'& .MuiOutlinedInput-root': { height: 40 }
}}
renderInput={(params) => (
<TextField {...params}
<TextField
{...params}
label="Status"
InputLabelProps={{ shrink: true }}
/>
)}
InputLabelProps={{
shrink: true
}}
/>
</Grid>

@@ -396,11 +399,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss
inputValue={orgSelected ? orgSelected.name!=undefined?orgSelected.name:"" : ""}

onChange={(event, newValue) => {
if (newValue !== null) {
setOrgSelected(newValue);
}else{
setOrgSelected({});
}
setOrgSelected(newValue ?? null);
}}
sx={{
'& .MuiInputBase-root': { alignItems: 'center' },


+ 12
- 1
src/pages/Proof/Search_Public/DataGrid.js Dosyayı Görüntüle

@@ -100,6 +100,10 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
}


const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const columns = [
{
field: 'actions',
@@ -107,6 +111,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
width: isMdOrLg ? 'auto' : 200,
flex: isMdOrLg ? 1.5 : undefined,
cellClassName: 'actions',
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return clickableLink('/proof/reply/' + params.row.id, params.row.refNo);
},
@@ -117,6 +122,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: isORGLoggedIn() ? intl.formatMessage({ id: 'gazetteCount3' }) : intl.formatMessage({ id: 'gazetteCount2' }),
width: isMdOrLg ? 'auto' : 330,
flex: isMdOrLg ? 2 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
// let appNo = params.row.appNo;
// let code = params.row.groupNo;
@@ -132,6 +138,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: intl.formatMessage({ id: 'proofDate' }),
width: isMdOrLg ? 'auto' : 200,
flex: isMdOrLg ? 1.5 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return DateUtils.datetimeStr(params?.value);
}
@@ -142,6 +149,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: intl.formatMessage({ id: 'replyBefore' }),
width: isMdOrLg ? 'auto' : 200,
flex: isMdOrLg ? 1.5 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
const proofPaymentDeadline = DateUtils.convertToDate(params?.value);
return DateUtils.datetimeStr(
@@ -156,15 +164,17 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: intl.formatMessage({ id: 'replyDate' }),
width: isMdOrLg ? 'auto' : 200,
flex: isMdOrLg ? 1.5 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return params?.value ? DateUtils.datetimeStr(params?.value) : "";
}
},
{
id: 'actions',
field: 'proofStatus',
headerName: intl.formatMessage({ id: 'status' }),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return locale === 'en' ? ProofStatus.getStatus_Eng(params) : locale === 'zh-HK' ? ProofStatus.getStatus_Cht(params) : ProofStatus.getStatus_Cn(params);
},
@@ -175,6 +185,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: intl.formatMessage({ id: 'fee' }),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return (params?.value) ? "$ " + FormatUtils.currencyFormat(params?.value) : "";
}


+ 19
- 9
src/pages/Proof/Search_Public/SearchForm.js Dosyayı Görüntüle

@@ -29,7 +29,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o
const [type, setType] = React.useState([]);
const [status, setStatus] = React.useState(searchCriteria.statusKey!=undefined?ComboData.proofStatusFull[searchCriteria.statusKey]:ComboData.proofStatusFull[0]);
const [issueSelected, setIssueSelected] = React.useState({});
const [issueSelected, setIssueSelected] = React.useState(null);
const [issueCombo, setIssueCombo] = React.useState([]);
const [groupSelected, setGroupSelected] = React.useState(searchCriteria.gazettGroup!=undefined?ComboData.groupTitle.find(item => item.code === searchCriteria.gazettGroup):{});

@@ -110,7 +110,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o
if (issueComboData && issueComboData.length > 0) {
setIssueCombo(issueComboData);
if(searchCriteria.issueId!=undefined){
setIssueSelected(issueComboData.find(item => item.id === searchCriteria.issueId))
setIssueSelected(issueComboData.find(item => item.id === searchCriteria.issueId) ?? null)
}
}
}, [issueComboData]);
@@ -118,7 +118,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o
function resetForm() {
setType([]);
setStatus(ComboData.proofStatusFull[0]);
setIssueSelected({});
setIssueSelected(null);
setGroupSelected({});
setMinDate(DateUtils.dateValue(new Date().setDate(new Date().getDate()-14)))
setMaxDate(DateUtils.dateValue(new Date()))
@@ -205,8 +205,9 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o
id="issueId"
options={issueCombo}
value={issueSelected}
isOptionEqualToValue={(option, value) => option?.id === value?.id}
inputValue={(issueSelected?.id) ? getIssueLabel(issueSelected) : ""}
getOptionLabel={(option) => getIssueLabel(option)}
getOptionLabel={(option) => (option?.id ? getIssueLabel(option) : "")}
onChange={(event, newValue) => {
setIssueSelected(newValue);
}}
@@ -223,6 +224,10 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o
}}
/>
)}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
/>
</Grid>

@@ -252,7 +257,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o
<Grid item xs={12} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<Grid container spacing={1}>
<Grid item xs={6}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateFrom"
@@ -279,7 +284,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o
</Grid>

<Grid item xs={6}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateTo"
@@ -348,11 +353,16 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o
renderInput={(params) => (
<TextField {...params}
label={intl.formatMessage({id: 'status'})}
InputLabelProps={{
...params.InputLabelProps,
shrink: true
}}
/>
)}
InputLabelProps={{
shrink: true
}}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
/>
</Grid>



+ 4
- 2
src/pages/Proof/Search_Public/index.js Dosyayı Görüntüle

@@ -17,6 +17,7 @@ const SearchForm = Loadable(React.lazy(() => import('./SearchForm')));
const EventTable = Loadable(React.lazy(() => import('./DataGrid')));
import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
import {FormattedMessage} from "react-intl";
import usePageTitle from "components/usePageTitle";

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
@@ -31,7 +32,8 @@ const BackgroundHead = {
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const UserSearchPage_Individual = () => {

usePageTitle("proofRecord");
const [issueCombo,setIssueCombo] = React.useState([]);
const [searchCriteria, setSearchCriteria] = React.useState({
dateTo: DateUtils.dateValue(new Date()),
@@ -87,7 +89,7 @@ const UserSearchPage_Individual = () => {
<Grid item xs={12}>
<div style={BackgroundHead} >
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center" >
<Typography ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
<FormattedMessage id="proofRecord"/>
</Typography>
</Stack>


+ 6
- 5
src/pages/PublicNotice/ApplyForm/PublicNoticeApplyForm.js Dosyayı Görüntüle

@@ -282,7 +282,7 @@ const PublicNoticeApplyForm = ({ loadedData, _selections, gazetteIssueList }) =>
<Grid item xs={12} md={12} width="100%" >
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' } }}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' } }}>
<FormattedMessage id="applyPublicNotice" />
</Typography>
</Stack>
@@ -566,6 +566,7 @@ const PublicNoticeApplyForm = ({ loadedData, _selections, gazetteIssueList }) =>
label: intl.formatMessage({ id: 'careOf' }) + ":",
valueName: "careOf",
form: formik,
inputProps: { "aria-label": intl.formatMessage({ id: 'careOf' }) }
// disabled: true
})}
</Grid>
@@ -593,7 +594,7 @@ const PublicNoticeApplyForm = ({ loadedData, _selections, gazetteIssueList }) =>
label: intl.formatMessage({ id: 'extraMark' }) + ":",
valueName: "remarks",
form: formik,
inputProps: { maxLength: 255 }
inputProps: { maxLength: 255, "aria-label": intl.formatMessage({ id: 'extraMark' }) }
})}
</Grid>
}
@@ -622,6 +623,9 @@ const PublicNoticeApplyForm = ({ loadedData, _selections, gazetteIssueList }) =>
name="tickAccept"
color="primary"
size="small"
inputProps={{
"aria-label": intl.formatMessage({ id: "applyTickStr" })
}}
/>
<Typography variant="h6" height="100%" >
<div style={{ padding: 12, textAlign: 'justify' }} dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: "applyTickStr" }) }} />
@@ -651,9 +655,6 @@ const PublicNoticeApplyForm = ({ loadedData, _selections, gazetteIssueList }) =>
</Typography>
</Grid>




</Grid>
</form>
) : null}


+ 5
- 3
src/pages/PublicNotice/ApplyForm/index.js Dosyayı Görüntüle

@@ -16,7 +16,7 @@ import Loadable from 'components/Loadable';
import { lazy } from 'react';
const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingComponent')));
const PublicNoticeApplyForm = Loadable(lazy(() => import('./PublicNoticeApplyForm')));
import usePageTitle from "components/usePageTitle";
import {
// isORGLoggedIn,
isDummyLoggedIn,
@@ -27,6 +27,8 @@ import {
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const ApplyForm = () => {
usePageTitle("applyPublicNotice");
const [userData, setUserData] = React.useState(null);
const [gazetteIssueList, setGazetteIssueList] = React.useState([]);

@@ -62,7 +64,7 @@ const ApplyForm = () => {
for (var i = 0; i < response?.gazetteIssueList?.length; i++) {
let data = response.gazetteIssueList[i];
//let label = getIssueLabel(data);
selection.push(<FormControlLabel value={data.id} control={<Radio />} label={getIssueLabel(data)} />);
selection.push(<FormControlLabel key={data.id} value={data.id} control={<Radio />} label={getIssueLabel(data)} />);
}
setGazetteIssueList(response?.gazetteIssueList);
setSelection(selection);
@@ -78,7 +80,7 @@ const ApplyForm = () => {
for (var i = 0; i < gazetteIssueList?.length; i++) {
let data = gazetteIssueList[i];
let label = getIssueLabel(data);
selection.push(<FormControlLabel value={data.id} control={<Radio />} label={label} />);
selection.push(<FormControlLabel key={data.id} value={data.id} control={<Radio />} label={label} />);
}
setSelection(selection);
}


+ 76
- 40
src/pages/PublicNotice/Details_GLD/ApplicationDetailCard.js Dosyayı Görüntüle

@@ -9,6 +9,7 @@ import {
Stack,
Dialog, DialogTitle, DialogContent, DialogActions, InputAdornment, Autocomplete
} from '@mui/material';
import LoadingButton from '@mui/lab/LoadingButton';
import { isGranted, delBugMode, getPaymentMethodGLD} from "auth/utils";
const MainCard = Loadable(lazy(() => import('components/MainCard')));
import { useForm } from "react-hook-form";
@@ -33,18 +34,46 @@ import CloseIcon from '@mui/icons-material/Close';
import EditNoteIcon from '@mui/icons-material/EditNote';
import DownloadIcon from '@mui/icons-material/Download';
import ReplayIcon from '@mui/icons-material/Replay';
import { notifyDownloadSuccess } from 'utils/CommonFunction';
import { notifyActionError } from 'utils/CommonFunction';
import { isGrantedAny } from "auth/utils";
// import { useIntl } from "react-intl";
import { useIntl } from "react-intl";

/** Contained buttons with custom bg must restyle disabled/loading or they stay green/orange. */
const publishWithdrawLoadingSx = (mainBg, hoverBg) => (theme) => ({
textTransform: 'capitalize',
alignItems: 'end',
backgroundColor: mainBg,
color: '#fff',
'&:hover:not(.Mui-disabled):not(.MuiLoadingButton-loading)': {
backgroundColor: hoverBg,
},
'&.Mui-disabled, &.MuiLoadingButton-loading': {
backgroundColor: theme.palette.action.disabledBackground,
color: theme.palette.action.disabled,
},
'&.Mui-disabled .MuiSvgIcon-root, &.MuiLoadingButton-loading .MuiSvgIcon-root': {
color: theme.palette.action.disabled,
},
'&.Mui-disabled .MuiTypography-root, &.MuiLoadingButton-loading .MuiTypography-root': {
color: `${theme.palette.action.disabled} !important`,
},
});

// ==============================|| DASHBOARD - DEFAULT ||============================== //
const ApplicationDetailCard = (
{ applicationDetailData,
setStatus,
setUploadStatus
setUploadStatus,
statusDialogOpen = false,
statusDialogKind = "",
statusActionLoading = false,
}
) => {

const publishWithdrawBusy =
statusActionLoading ||
(statusDialogOpen && (statusDialogKind === 'publish' || statusDialogKind === 'withdraw'));

const [currentApplicationDetailData, setCurrentApplicationDetailData] = useState({});
const [companyName, setCompanyName] = useState({});
const [orgDetail, setOrgDetail] = useState({});
@@ -59,13 +88,15 @@ const ApplicationDetailCard = (
const [mode, setMode] = useState("");

const { register, handleSubmit } = useForm()
// const intl = useIntl();
const intl = useIntl();

const [isWarningPopUp, setIsWarningPopUp] = useState(false);
const [warningText, setWarningText] = useState("");

const [remarksPopUp, setRemarksPopUp] = useState(false);
const [onDownload, setOnDownload] = useState(false);
// eslint-disable-next-line no-unused-vars -- isProofCheckLoading in onProofClick + Button disabled; setIsProofCheckLoading in onProofClick callbacks
const [isProofCheckLoading, setIsProofCheckLoading] = useState(false);

useEffect(() => {
//if user data from parent are not null
@@ -125,12 +156,12 @@ const ApplicationDetailCard = (
fileId: fileDetail?.id,
skey: fileDetail?.skey,
filename: fileDetail?.filename,
onResponse:()=>{
setOnDownload(false)
notifyDownloadSuccess()
onResponse: () => {
setOnDownload(false);
},
onError:()=>{
setOnDownload(false)
onError: () => {
setOnDownload(false);
notifyActionError(intl.formatMessage({ id: 'downloadFailed' }));
}
});
setUploadStatus(true)
@@ -166,10 +197,12 @@ const ApplicationDetailCard = (
};

const withdrawnClick = () => () => {
if (publishWithdrawBusy) return;
setStatus("withdraw")
};

const doPublish = () => () => {
if (publishWithdrawBusy) return;
setStatus("publish")
}

@@ -178,10 +211,13 @@ const ApplicationDetailCard = (
};

const onProofClick = () => {
if (isProofCheckLoading) return;
if (applicationDetailData.data.groupNo) {
setIsProofCheckLoading(true);
HttpUtils.get({
url: CHECK_CREATE_PROOF + "/" + currentApplicationDetailData.id,
onSuccess: function (responeData) {
setIsProofCheckLoading(false);
if (responeData.success == true) {
window.open("/proof/create/" + currentApplicationDetailData.id, "_blank", "noreferrer");
window.addEventListener("focus", onFocus)
@@ -190,12 +226,16 @@ const ApplicationDetailCard = (
if (msg === "haveActiveProof") {
msg = "Action Failed: There is already a pending payment and proofreading record for client review."
} else if (msg === "haveProofed") {
msg = "Action Failed: Already proofed."
msg = "Action Failed: An active proof is already created for this application."
} else {
msg = intl.formatMessage({ id: msg });
}
setWarningText(msg);
setIsWarningPopUp(true);
}
}
},
onFail: () => setIsProofCheckLoading(false),
onError: () => setIsProofCheckLoading(false)
});
} else {
setWarningText("Please generate Gazette Code before Create Proof.");
@@ -256,6 +296,7 @@ const ApplicationDetailCard = (
<Button
// size="large"
variant="contained"
disabled={isProofCheckLoading}
onClick={() => { onProofClick() }}
sx={{
textTransform: 'capitalize',
@@ -324,31 +365,26 @@ const ApplicationDetailCard = (
</> :
(currentApplicationDetailData.status == "confirmed" && currentApplicationDetailData.creditor == 1) ?
<>
<Button
<LoadingButton
// size="large"
variant="contained"
onClick={doPublish()}
disabled={setCompleteDisable()}
sx={{
textTransform: 'capitalize',
alignItems: 'end',
backgroundColor: '#52b202'
}}>
disabled={setCompleteDisable() || publishWithdrawBusy}
loading={statusActionLoading && statusDialogKind === 'publish'}
sx={publishWithdrawLoadingSx('#52b202', '#489f04')}>
<DoneIcon />
<Typography ml={1} variant="h5">Publish</Typography>
</Button>
<Button
</LoadingButton>
<LoadingButton
// size="large"
variant="contained"
onClick={withdrawnClick()}
sx={{
textTransform: 'capitalize',
alignItems: 'end',
backgroundColor: '#ffa733'
}}>
disabled={publishWithdrawBusy}
loading={statusActionLoading && statusDialogKind === 'withdraw'}
sx={publishWithdrawLoadingSx('#ffa733', '#e8982e')}>
<CloseIcon />
<Typography ml={1} variant="h5">Withdraw</Typography>
</Button>
</LoadingButton>
</>
:
(
@@ -382,18 +418,16 @@ const ApplicationDetailCard = (
<DoneIcon />
<Typography ml={1} variant="h5">Publish</Typography>
</Button>
<Button
<LoadingButton
// size="large"
variant="contained"
onClick={withdrawnClick()}
sx={{
textTransform: 'capitalize',
alignItems: 'end',
backgroundColor: '#ffa733'
}}>
disabled={publishWithdrawBusy}
loading={statusActionLoading && statusDialogKind === 'withdraw'}
sx={publishWithdrawLoadingSx('#ffa733', '#e8982e')}>
<CloseIcon />
<Typography ml={1} variant="h5">Withdraw</Typography>
</Button>
</LoadingButton>
</> : null
)
}
@@ -715,7 +749,11 @@ const ApplicationDetailCard = (
sx={{
textTransform: 'capitalize',
alignItems: 'end',
}}>
backgroundColor: '#0C489E',
color: '#FFFFFF',
'&:hover': { backgroundColor: '#093A7A' },
}}
>
<DownloadIcon />
</Button>
</Grid>
@@ -841,7 +879,7 @@ const ApplicationDetailCard = (
}
}}
>
<DialogTitle><Typography variant="h3">Warning</Typography></DialogTitle>
<DialogTitle component="div"><Typography variant="h3">Warning</Typography></DialogTitle>
<DialogContent style={{ display: 'flex', }}>
<Typography variant="h4" style={{ padding: '16px' }}>{warningText}</Typography>
</DialogContent>
@@ -863,7 +901,7 @@ const ApplicationDetailCard = (
}}
>
<form onSubmit={handleSubmit(onSubmit)}>
<DialogTitle><Typography variant="h3">Remarks</Typography></DialogTitle>
<DialogTitle component="div"><Typography variant="h3">Remarks</Typography></DialogTitle>
<DialogContent style={{ display: 'flex', }}>
<Grid container direction="column">
<Grid item sx={{ padding: '16px' }}>
@@ -914,7 +952,7 @@ const ApplicationDetailCard = (
filterOptions={(options) => options}
options={ComboData.paymentMeans}
value={paymentMeans}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
inputValue={paymentMeans?.label ? paymentMeans?.label : ""}
onChange={(event, newValue) => {
setPaymentMeans(newValue);
@@ -927,11 +965,9 @@ const ApplicationDetailCard = (
renderInput={(params) => (
<TextField {...params}
label=""
InputLabelProps={{ shrink: true }}
/>
)}
InputLabelProps={{
shrink: true,
}}
disableClearable={true}
/>
</Grid>


+ 14
- 5
src/pages/PublicNotice/Details_GLD/GazetteDetailCard.js Dosyayı Görüntüle

@@ -20,12 +20,14 @@ const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingCo
import * as DateUtils from "utils/DateUtils";
import EditNoteIcon from '@mui/icons-material/EditNote';
import { isGrantedAny } from "auth/utils";
import { useIntl } from "react-intl";
// ==============================|| DASHBOARD - DEFAULT ||============================== //
const GazetteDetailCard = (
{ applicationDetailData,
setStatus
}
) => {
const intl = useIntl();
const [onReady, setOnReady] = useState(false);
const [issueNum, setIssueNum] = useState("");
const [issueDate, setIssueDate] = useState("");
@@ -51,11 +53,11 @@ const GazetteDetailCard = (
setIssueNum(applicationDetailData.gazetteIssueDetail.volume + "/" + applicationDetailData.gazetteIssueDetail.issueYear
+ " No. " + applicationDetailData.gazetteIssueDetail.issueNo);
setIssueDate(DateUtils.dateFormat(applicationDetailData.gazetteIssueDetail.issueDate, "D MMM YYYY (ddd)"));
setGazetteCode(applicationDetailData.data.groupNo)
setGazetteCode(applicationDetailData.data.groupNo ?? '')
// console.log(applicationDetailData)
setSysType(applicationDetailData.userData.sysType)
setCareOf(applicationDetailData.data.careOf)
setGroupTitle(applicationDetailData.data.groupTitle)
setCareOf(applicationDetailData.data.careOf ?? '')
setGroupTitle(applicationDetailData.data.groupTitle ?? '')
if (applicationDetailData.data.mode != null){
setMode(applicationDetailData.data.mode);
}
@@ -71,7 +73,11 @@ const GazetteDetailCard = (
}, [issueNum]);

const groupDetailClick = () => () => {
if (gazetteCode == null) {
// groupNo is normalized to '' when absent, so check empty string — not only null
const hasGazetteCode =
gazetteCode != null &&
String(gazetteCode).trim() !== "";
if (!hasGazetteCode) {
setStatus("genGazetteCode");
return;
}
@@ -275,6 +281,7 @@ const GazetteDetailCard = (
})}
value={careOf}
id='careOf'
inputProps={{ 'aria-label': intl.formatMessage({ id: 'careOf' }) }}
sx={{
"& .MuiInputBase-input.Mui-disabled": {
WebkitTextFillColor: "#000000",
@@ -303,7 +310,9 @@ const GazetteDetailCard = (
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' }
}
}}>
<DialogTitle><Typography variant="h3">Warning</Typography></DialogTitle>
<DialogTitle component="div">
<Typography variant="h3" component="h2">Warning</Typography>
</DialogTitle>
<DialogContent style={{ display: 'flex', }}>
<Typography variant="h4" style={{ padding: '16px' }}>{warningText}</Typography>
</DialogContent>


+ 61
- 21
src/pages/PublicNotice/Details_GLD/StatusChangeDialog.js Dosyayı Görüntüle

@@ -1,6 +1,7 @@
import {
useEffect,
useState
useState,
useRef
} from "react";

// material-ui
@@ -16,8 +17,9 @@ import {
FormLabel,
Autocomplete,
TextField,
Grid
Grid,
} from '@mui/material';
import LoadingButton from '@mui/lab/LoadingButton';

import * as ComboData from "utils/ComboData";
import { useFormik, FormikProvider } from 'formik';
@@ -30,8 +32,15 @@ const StatusChangeDialog = (props) => {
const [remarks, setRemarks] = useState("");
const [helperText, setHelperText] = useState("");
const [comboInputValue, setComboInputValue] = useState({});
const [positiveSubmitting, setPositiveSubmitting] = useState(false);
const positiveOnceRef = useRef(false);
const groupTitleComboList = ComboData.groupTitle;

const confirmLoading = Boolean(props.confirmLoading) || positiveSubmitting;
const gazetteGroupMissing =
props.getStatus === "genGazetteCode" &&
Object.keys(props.selectedGazetteGroup ?? {}).length === 0;

useEffect(() => {
setComboInputValue({});
if (props.getStatus == "genGazetteCode") {
@@ -58,22 +67,40 @@ const StatusChangeDialog = (props) => {
}
}, [props.getStatus]);

useEffect(() => {
if (!props.open) {
positiveOnceRef.current = false;
setPositiveSubmitting(false);
}
}, [props.open]);

const wasConfirmLoadingRef = useRef(false);
useEffect(() => {
if (wasConfirmLoadingRef.current && !props.confirmLoading) {
positiveOnceRef.current = false;
setPositiveSubmitting(false);
}
wasConfirmLoadingRef.current = Boolean(props.confirmLoading);
}, [props.confirmLoading]);

const acceptedHandle = () => () => {
const getStatus = props.getStatus.status;
if (getStatus == "notAccepted") {
if (!remarks || remarks == "")
if (confirmLoading) return;
if (positiveOnceRef.current) return;

const statusKey = props.getStatus;

if (statusKey === "notAccepted" || statusKey === "resubmit") {
if (!remarks || remarks === "") {
setHelperText("Please enter reason");
}
if (!helperText) {
props.setReason({ "reason": remarks });
if (remarks != null && remarks != "") {
// console.log(remarks)
// props.setStatusWindowAccepted(true);
return;
}
setHelperText("");
props.setReason({ "reason": remarks });
}
if (getStatus != "notAccepted") {
props.setStatusWindowAccepted(true);
}

positiveOnceRef.current = true;
setPositiveSubmitting(true);
props.setStatusWindowAccepted(true);
};


@@ -147,6 +174,11 @@ const StatusChangeDialog = (props) => {
id="gazetteGroup"
options={groupTitleComboList}
filterOptions={(options) => options}
getOptionLabel={(option) => {
if (option == null) return "";
if (typeof option === "string") return option;
return option.label != null ? String(option.label) : "";
}}
inputValue={comboInputValue.label}
onChange={(event, newValue) => {
if (newValue != null && newValue != {}) {
@@ -156,7 +188,6 @@ const StatusChangeDialog = (props) => {
props.setSelectedGazetteGroup(newValue);
formik.setFieldValue("", "")
} else {
gazetteGroup
props.setSelectedGazetteGroupInputType("");
}
}}
@@ -177,7 +208,10 @@ const StatusChangeDialog = (props) => {
return (
<Dialog
open={props.open}
onClose={props.handleClose}
onClose={() => {
if (confirmLoading) return;
props.handleClose();
}}
fullWidth={true}
maxWidth={'md'}
>
@@ -195,7 +229,7 @@ const StatusChangeDialog = (props) => {
<FormikProvider value={formik}>
<form>
<DialogContent>
<DialogContentText>
<DialogContentText component="div">
{content}
</DialogContentText>
</DialogContent>
@@ -203,18 +237,24 @@ const StatusChangeDialog = (props) => {
</FormikProvider>
<Stack direction="row" justifyContent="space-around">
<DialogActions>
<Button variant="contained" onClick={props.handleClose} autoFocus >
<Button variant="contained" onClick={props.handleClose} autoFocus disabled={confirmLoading}>
<Typography variant="h5">
Cancel
</Typography>
</Button>
</DialogActions>
<DialogActions>
<Button variant="contained" color="success" onClick={acceptedHandle()} autoFocus disabled={Object.keys(props.selectedGazetteGroup).length === 0 && props.getStatus === "genGazetteCode"}>
<Typography variant="h5">
<LoadingButton
variant="contained"
color="success"
onClick={acceptedHandle()}
loading={confirmLoading}
disabled={gazetteGroupMissing}
>
<Typography variant="h5" component="span">
{prositiveBtnText}
</Typography>
</Button>
</LoadingButton>
</DialogActions>
</Stack>
</Dialog>


+ 115
- 21
src/pages/PublicNotice/Details_GLD/index.js Dosyayı Görüntüle

@@ -70,6 +70,7 @@ const PublicNoticeDetail_GLD = () => {
const [open, setOpen] = useState(false);
const [getStatus, setStatus] = useState("");
const [statusWindowAccepted, setStatusWindowAccepted] = useState(false);
const [statusConfirmLoading, setStatusConfirmLoading] = useState(false);
const [selectedGazetteGroup, setSelectedGazetteGroup] = useState({});
const [selectedGazetteGroupInputType, setSelectedGazetteGroupInputType] = useState("");
const [getReason, setReason] = useState({});
@@ -182,24 +183,30 @@ const PublicNoticeDetail_GLD = () => {
};

useEffect(() => {
if (statusWindowAccepted) {
if (getStatus == "genGazetteCode") {
onAcceptedClick()
} else if (getStatus == "complete") {
onComplatedClick()
} else if (getStatus == "withdraw") {
onWithdrawnClick()
} else if (getStatus == "notAccepted") {
onNotAcceptClick(getReason);
} else if (getStatus == "resubmit") {
onReSubmitClick(getReason);
} else if (getStatus == "publish") {
onPublishClick();
} else if (getStatus == "revoke") {
onRevokeClick();
} else if(getStatus == "paid"){
onPaidClick();
}
if (!statusWindowAccepted) {
setStatusConfirmLoading(false);
return;
}
setStatusConfirmLoading(true);
if (getStatus == "genGazetteCode") {
onAcceptedClick()
} else if (getStatus == "complete") {
onComplatedClick()
} else if (getStatus == "withdraw") {
onWithdrawnClick()
} else if (getStatus == "notAccepted") {
onNotAcceptClick(getReason);
} else if (getStatus == "resubmit") {
onReSubmitClick(getReason);
} else if (getStatus == "publish") {
onPublishClick();
} else if (getStatus == "revoke") {
onRevokeClick();
} else if(getStatus == "paid"){
onPaidClick();
} else {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
}
}, [statusWindowAccepted]);

@@ -223,12 +230,23 @@ const PublicNoticeDetail_GLD = () => {
.catch(error => {
console.log(error);
return false;
})
.finally(() => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
});
} else {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
}
};

const onNotAcceptClick = (reason) => {
if (params.id <= 0) return;
if (params.id <= 0) {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
return;
}
HttpUtils.post({
url: `${SET_PUBLIC_NOTICE_STATUS_NOT_ACCEPT}/${params.id}`,
params: reason,
@@ -238,12 +256,24 @@ const PublicNoticeDetail_GLD = () => {
// location.reload();
loadApplicationDetail()
notifySaveSuccess()
},
onFail: () => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
},
onError: () => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
}
});
}

const onPublishClick = () => {
if (params.id <= 0) return;
if (params.id <= 0) {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
return;
}
HttpUtils.get({
url: `${SET_PUBLIC_NOTICE_STATUS_PUBLISH}/${params.id}`,
onSuccess: function () {
@@ -251,6 +281,18 @@ const PublicNoticeDetail_GLD = () => {
handleClose();
loadApplicationDetail()
notifySaveSuccess()
},
onFail: () => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
},
onError: () => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
},
onFinally: () => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
}
});
}
@@ -270,7 +312,14 @@ const PublicNoticeDetail_GLD = () => {
.catch(error => {
console.log(error);
return false;
})
.finally(() => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
});
} else {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
}
};

@@ -289,7 +338,14 @@ const PublicNoticeDetail_GLD = () => {
.catch(error => {
console.log(error);
return false;
})
.finally(() => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
});
} else {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
}
};

@@ -307,7 +363,14 @@ const PublicNoticeDetail_GLD = () => {
.catch(error => {
console.log(error);
return false;
})
.finally(() => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
});
} else {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
}
};

@@ -322,6 +385,14 @@ const PublicNoticeDetail_GLD = () => {
// location.reload();
loadApplicationDetail()
notifySaveSuccess()
},
onFail: () => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
},
onError: () => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
}
});
// axios.post(`${SET_PUBLIC_NOTICE_STATUS_RESUBMIT}/${params.id}`)
@@ -338,11 +409,18 @@ const PublicNoticeDetail_GLD = () => {
// console.log(error);
// return false;
// });
} else {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
}
};

const onRevokeClick = () => {
if (params.id <= 0) return;
if (params.id <= 0) {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
return;
}
HttpUtils.get({
url: `${SET_PUBLIC_NOTICE_STATUS_REVOKE}/${params.id}`,
onSuccess: function () {
@@ -350,6 +428,18 @@ const PublicNoticeDetail_GLD = () => {
handleClose();
loadApplicationDetail()
notifySaveSuccess()
},
onFail: () => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
},
onError: () => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
},
onFinally: () => {
setStatusConfirmLoading(false);
setStatusWindowAccepted(false);
}
});
}
@@ -383,6 +473,7 @@ const PublicNoticeDetail_GLD = () => {
issueDate={issueDate}
issueNum={issueNum}
gazetteIssue={gazetteIssue}
confirmLoading={statusConfirmLoading}
//combo value
selectedGazetteGroup={selectedGazetteGroup}
setSelectedGazetteGroup={setSelectedGazetteGroup}
@@ -425,6 +516,9 @@ const PublicNoticeDetail_GLD = () => {
setUpdateApplicationObject={setUpdateApplicationObject}
isEditMode={isEditMode}
setiIsSave={setiIsSave}
statusDialogOpen={open}
statusDialogKind={getStatus}
statusActionLoading={statusConfirmLoading}
// isNewRecord={isNewRecord}
/>
}


+ 8
- 0
src/pages/PublicNotice/Details_GLD/tabTableDetail/PaymentTab.js Dosyayı Görüntüle

@@ -17,6 +17,10 @@ export default function SubmittedTab({ appId, setCount }) {
const theme = useTheme();
const isMdOrLg = useMediaQuery(theme.breakpoints.up('md'));

const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const columns = [
{
field: 'actions',
@@ -24,6 +28,7 @@ export default function SubmittedTab({ appId, setCount }) {
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
cellClassName: 'actions',
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return clickableLink('/paymentPage/details/' + params.row.id, params.row.transNo);
},
@@ -34,6 +39,7 @@ export default function SubmittedTab({ appId, setCount }) {
headerName: 'Trans. Date',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return DateUtils.datetimeStr(params.value);
}
@@ -44,6 +50,7 @@ export default function SubmittedTab({ appId, setCount }) {
headerName: 'Status',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return PaymentStatus.getStatus_Eng(params);
}
@@ -53,6 +60,7 @@ export default function SubmittedTab({ appId, setCount }) {
field: 'payAmount',
headerName: 'Amount',
width: 150,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return (params?.value) ? "$ " + FormatUtils.currencyFormat(params?.value) : "";
}


+ 11
- 2
src/pages/PublicNotice/Details_GLD/tabTableDetail/ProofTab.js Dosyayı Görüntüle

@@ -28,6 +28,10 @@ export default function ProofTab({appId, setCount}) {
});
};

const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const columns = [
{
@@ -36,6 +40,7 @@ export default function ProofTab({appId, setCount}) {
width: isMdOrLg ? 'auto' : 200,
flex: isMdOrLg ? 1 : undefined,
cellClassName: 'actions',
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return clickableLink('/proof/reply/' + params.row.id, params.row.refNo);
},
@@ -45,6 +50,7 @@ export default function ProofTab({appId, setCount}) {
headerName: 'Status',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return ProofStatus.getStatus_Eng(params);
},
@@ -54,7 +60,7 @@ export default function ProofTab({appId, setCount}) {
headerName: 'Proof Issue Date',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return DateUtils.datetimeStr(params?.value);
}
@@ -64,6 +70,7 @@ export default function ProofTab({appId, setCount}) {
headerName: 'Confirmed/Return Date',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return params?.value?DateUtils.datetimeStr(params?.value):"";
}
@@ -73,15 +80,17 @@ export default function ProofTab({appId, setCount}) {
headerName: 'Fee',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return (params?.value)?"$ "+FormatUtils.currencyFormat(params?.value):"";
}
},
{
field: 'actions',
type: 'actions',
headerName: 'Proof Slip',
width: 100,
renderHeader: renderHeaderWithAria,
cellClassName: 'actions',
getActions: (params) => {
if(params.row.action == null) return[];


+ 8
- 1
src/pages/PublicNotice/Details_GLD/tabTableDetail/StatusHistoryTab.js Dosyayı Görüntüle

@@ -13,6 +13,10 @@ export default function StatusHistoryTab({appId, setCount}) {
const theme = useTheme();
const isMdOrLg = useMediaQuery(theme.breakpoints.up('md'));

const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const columns = [
{
id: 'created',
@@ -20,6 +24,7 @@ export default function StatusHistoryTab({appId, setCount}) {
headerName: 'Date',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return DateUtils.datetimeStr(params?.value);
}
@@ -31,6 +36,7 @@ export default function StatusHistoryTab({appId, setCount}) {
headerName: 'Changed By',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
},
{
id: 'status',
@@ -38,8 +44,9 @@ export default function StatusHistoryTab({appId, setCount}) {
headerName: 'Status',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return [StatusUtils.getStatusEng(params)]
return StatusUtils.getStatusEng(params);
},
},
];


+ 6
- 5
src/pages/PublicNotice/Details_GLD/tabTableDetail/TabTable.js Dosyayı Görüntüle

@@ -9,6 +9,7 @@ import {

import { TabPanel, TabContext, TabList } from '@mui/lab';
import {useState, useEffect, lazy} from "react";
import { useIntl } from 'react-intl';

import Loadable from 'components/Loadable';
const LoadingComponent = Loadable(lazy(() => import('../../../extra-pages/LoadingComponent')));
@@ -20,7 +21,7 @@ const StatusHistoryTab = Loadable(lazy(() => import('./StatusHistoryTab')));
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const PublicNotice = ({ appId, proofCount, paymentCount, statusHistoryCount, setProofCount, setPaymentCount, setStatusHistoryCount }) => {
const intl = useIntl();
const [onReady, setOnReady] = useState(false);
const [selectedTab, setSelectedTab] = useState("1");

@@ -41,10 +42,10 @@ const PublicNotice = ({ appId, proofCount, paymentCount, statusHistoryCount, set
<Grid item xs={12}>
<TabContext value={selectedTab}>
<Box sx={{ borderBottom: 1, borderColor: 'divider', overflowX: 'auto' }}>
<TabList onChange={handleChange} aria-label="lab API tabs example">
<Tab renderActiveOnly={false} label={"Proof (" + proofCount + ") "} value="1" />
<Tab renderActiveOnly={false} label={"Online Payment (" + paymentCount + ") "} value="2" />
<Tab renderActiveOnly={false} label={"Status History (" + statusHistoryCount + ") "} value="3" />
<TabList onChange={handleChange} aria-label={intl.formatMessage({ id: 'ariaRelatedRecords' })}>
<Tab label={"Proof (" + proofCount + ") "} value="1" />
<Tab label={"Online Payment (" + paymentCount + ") "} value="2" />
<Tab label={"Status History (" + statusHistoryCount + ") "} value="3" />
</TabList>
</Box>
<TabPanel value="1" sx={{ p: 0 }}>


+ 14
- 4
src/pages/PublicNotice/Details_Public/ApplicationDetailCard.js Dosyayı Görüntüle

@@ -222,7 +222,6 @@ const ApplicationDetailCard = (
<Button
variant="contained"
onClick={cancelledClick()}
color="edit"
disabled={currentApplicationDetailData.status == "rejected"
|| currentApplicationDetailData.status == "cancelled"
|| currentApplicationDetailData.status == "withdrawn"
@@ -239,6 +238,11 @@ const ApplicationDetailCard = (
title={intl.formatMessage({ id: 'cancelApp' })}
startIcon={<CloseIcon />}
aria-label={intl.formatMessage({ id: 'cancelApp' })}
sx={{
backgroundColor: '#0C489E',
color: '#FFFFFF',
'&:hover': { backgroundColor: '#093A7A' },
}}
>
<FormattedMessage id="cancelApp" />
</Button>
@@ -651,20 +655,24 @@ const ApplicationDetailCard = (
<Grid container direction="row" alignItems="center" justifyContent="flex-start">
<Grid item xs={12} sm={12} md={12} lg={12} sx={{ wordBreak: 'break-word', }}>
<Typography
fullWidth
id='fileName'
variant="pnspsFormParagraph"
sx={{ width: '100%' }}
>
{fileDetail?.filename}
</Typography>
<ThemeProvider theme={PNSPS_BUTTON_THEME}>
<Button
sx={{ ml: 3 }}
sx={{
ml: 3,
backgroundColor: '#0C489E',
color: '#FFFFFF',
'&:hover': { backgroundColor: '#093A7A' },
}}
variant="contained"
onClick={onDownloadClick()}
aria-label={intl.formatMessage({ id: 'download' })}
title={intl.formatMessage({ id: 'download' })}
color="save"
disabled={!fileDetail?.filename||onDownload}
startIcon={<DownloadIcon sx={{ alignItems: "center" }} />}
>
@@ -690,7 +698,9 @@ const ApplicationDetailCard = (
<FormControl variant="outlined" sx={{ width: '100%' }} disabled>
<OutlinedInput
size="small"
id="careOf"
value={currentApplicationDetailData.careOf}
inputProps={{ 'aria-label': intl.formatMessage({ id: 'careOf' }) }}
sx={{
"& .MuiInputBase-input.Mui-disabled": {
WebkitTextFillColor: "#000000",


+ 33
- 10
src/pages/PublicNotice/Details_Public/StatusChangeDialog.js Dosyayı Görüntüle

@@ -1,10 +1,12 @@
import {
useEffect,
useState
useState,
useRef
} from "react";

// material-ui
import {
Box,
Button,
// Link,
Stack,
@@ -14,7 +16,7 @@ import {
DialogContent,
DialogContentText,
DialogTitle,
FormLabel,
CircularProgress,
} from '@mui/material';
import { useFormik,FormikProvider } from 'formik';
import * as yup from 'yup';
@@ -26,6 +28,7 @@ import {useIntl} from "react-intl";
const StatusChangeDialog = (props) => {
const [status, setStatus] = useState("");
const intl = useIntl();
const confirmOnceRef = useRef(false);

useEffect(() => {
// console.log(Object.keys(!props.selectedGazetteGroup).length)
@@ -33,9 +36,25 @@ const StatusChangeDialog = (props) => {
setStatus(intl.formatMessage({id: 'cancel'}))
}
}, [props.getStatus]);

useEffect(() => {
if (!props.open) {
confirmOnceRef.current = false;
}
}, [props.open]);

const wasConfirmLoadingRef = useRef(false);
useEffect(() => {
if (wasConfirmLoadingRef.current && !props.confirmLoading) {
confirmOnceRef.current = false;
}
wasConfirmLoadingRef.current = props.confirmLoading;
}, [props.confirmLoading]);
const acceptedHandle = () => () =>{
// console.log(selectedGazetteGroup)
if (props.confirmLoading) return;
if (confirmOnceRef.current) return;
confirmOnceRef.current = true;
props.setStatusWindowAccepted(true)
};

@@ -60,19 +79,20 @@ const StatusChangeDialog = (props) => {
fullWidth={true}
maxWidth={'xs'}
>
<DialogTitle >
<Typography variant="h4">
<DialogTitle component="div">
<Typography variant="h4" component="h2">
{status} {intl.formatMessage({id: 'publicNotice'})}
</Typography>
</DialogTitle>
<FormikProvider value={formik}>
<form>
<DialogContent>
<DialogContentText>
<FormLabel sx={{fontSize: "18px", color:"#000000",textAlign:"center"}}>
<Typography variant="h5">
{intl.formatMessage({id: 'confirmTo'})}{status} {intl.formatMessage({id: 'publicNoticeApp'})}?</Typography>
</FormLabel>
<DialogContentText component="div">
<Box sx={{ fontSize: '18px', color: '#000000', textAlign: 'center' }}>
<Typography variant="h5" component="p" sx={{ m: 0 }}>
{intl.formatMessage({id: 'confirmTo'})}{status} {intl.formatMessage({id: 'publicNoticeApp'})}?
</Typography>
</Box>
</DialogContentText>
</DialogContent>
</form>
@@ -85,6 +105,7 @@ const StatusChangeDialog = (props) => {
onClick={props.handleClose}
autoFocus
color="cancel"
disabled={props.confirmLoading}
>
<FormattedMessage id="cancel"/>
</Button>
@@ -95,6 +116,8 @@ const StatusChangeDialog = (props) => {
color="save"
onClick={acceptedHandle()}
autoFocus
disabled={props.confirmLoading}
startIcon={props.confirmLoading ? <CircularProgress color="inherit" size={20} /> : null}
>
<FormattedMessage id="confirm"/>
</Button>


+ 22
- 4
src/pages/PublicNotice/Details_Public/index.js Dosyayı Görüntüle

@@ -1,6 +1,7 @@
import React, {
useEffect,
useState,
useRef,
lazy
} from "react";

@@ -32,10 +33,12 @@ import { useNavigate } from "react-router-dom";
import ForwardIcon from '@mui/icons-material/Forward';
import { notifyActionSuccess } from "utils/CommonFunction";
import { FormattedMessage, useIntl } from "react-intl";
import usePageTitle from "components/usePageTitle";
// ==============================|| Body - DEFAULT ||============================== //

const DashboardDefault = () => {
usePageTitle("myPublicNotice");
const params = useParams();
const [applicationDetailData, setApplicationDetailData] = useState({});
const [appNo, setAapNo] = useState("");
@@ -47,6 +50,8 @@ const DashboardDefault = () => {
const [open, setOpen] = useState(false);
const [getStatus, setStatus] = useState("");
const [statusWindowAccepted, setStatusWindowAccepted] = useState(false);
const [cancelLoading, setCancelLoading] = useState(false);
const cancellingRef = useRef(false);

const [proofCount, setProofCount] = useState(0);
const [paymentCount, setPaymentCount] = useState(0);
@@ -135,7 +140,10 @@ const DashboardDefault = () => {
}, [getStatus]);

const onCancelledClick = () => {
if (cancellingRef.current) return;
if (params.id > 0) {
cancellingRef.current = true;
setCancelLoading(true);
axios.get(`${SET_PUBLIC_NOTICE_STATUS_CANCELLED}/${params.id}`)
.then((response) => {
if (response.status === 204) {
@@ -149,17 +157,27 @@ const DashboardDefault = () => {
.catch(error => {
console.log(error);
return false;
})
.finally(() => {
cancellingRef.current = false;
setCancelLoading(false);
});
}
};

return (
<Grid container sx={{ backgroundColor: '#ffffff' }} direction="column">
<StatusChangeDialog open={open} handleClose={handleClose} setStatusWindowAccepted={setStatusWindowAccepted} getStatus={getStatus} />
<StatusChangeDialog
open={open}
handleClose={handleClose}
setStatusWindowAccepted={setStatusWindowAccepted}
getStatus={getStatus}
confirmLoading={cancelLoading}
/>
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' } }}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' } }}>
<FormattedMessage id="myPublicNotice" />
</Typography>
</Stack>
@@ -177,7 +195,7 @@ const DashboardDefault = () => {
>
<ForwardIcon style={{ height: 30, width: 50, transform: "rotate(180deg)" }} />
</Button>
<Typography ml={3} mt={3} variant="h4">{title}</Typography>
<Typography component="h2" ml={3} mt={3} variant="h4">{title}</Typography>
</Stack>
</Grid>
<Grid item width={{ md: "60%", xs: "90%" }}>


+ 8
- 0
src/pages/PublicNotice/Details_Public/tabTableDetail/PaymentTab.js Dosyayı Görüntüle

@@ -21,6 +21,10 @@ export default function SubmittedTab({ appId, setCount }) {
const { locale } = intl;

const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const columns = [
{
field: 'actions',
@@ -28,6 +32,7 @@ export default function SubmittedTab({ appId, setCount }) {
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
cellClassName: 'actions',
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return clickableLink('/paymentPage/details/' + params.row.id, params.row.transNo);
},
@@ -38,6 +43,7 @@ export default function SubmittedTab({ appId, setCount }) {
headerName: intl.formatMessage({id: 'payDate'}),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return DateUtils.datetimeStr(params.value);
}
@@ -48,6 +54,7 @@ export default function SubmittedTab({ appId, setCount }) {
headerName: intl.formatMessage({id: 'payStatus'}),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return locale === 'en' ? PaymentStatus.getStatus_Eng(params):PaymentStatus.getStatus_Cht(params);
}
@@ -57,6 +64,7 @@ export default function SubmittedTab({ appId, setCount }) {
field: 'payAmount',
headerName: intl.formatMessage({id: 'fee'}),
width: 150,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return (params?.value) ? "$ " + FormatUtils.currencyFormat(params?.value) : "";
}


+ 10
- 3
src/pages/PublicNotice/Details_Public/tabTableDetail/ProofTab.js Dosyayı Görüntüle

@@ -19,23 +19,27 @@ export default function ProofTab({appId, setCount}) {
const isMdOrLg = useMediaQuery(theme.breakpoints.up('md'));
const { locale } = intl;

const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const columns = [
{
field: 'actions',
field: 'refNo',
headerName: intl.formatMessage({id: 'proofId'}),
width: 200,
cellClassName: 'actions',
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return clickableLink('/proof/reply/' + params.row.id, params.row.refNo);
},
},
{
id: 'actions',
field: 'status',
headerName: intl.formatMessage({id: 'status'}),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return locale === 'en' ? ProofStatus.getStatus_Eng(params) : ProofStatus.getStatus_Cht(params);
},
@@ -46,6 +50,7 @@ export default function ProofTab({appId, setCount}) {
headerName: intl.formatMessage({id: 'proofDate'}),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return DateUtils.datetimeStr(params?.value);
}
@@ -56,6 +61,7 @@ export default function ProofTab({appId, setCount}) {
headerName: intl.formatMessage({id: 'replyDate'}),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return params?.value?DateUtils.datetimeStr(params?.value):"";
}
@@ -66,6 +72,7 @@ export default function ProofTab({appId, setCount}) {
headerName: intl.formatMessage({id: 'fee'}),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return (params?.value)?"$ "+FormatUtils.currencyFormat(params?.value):"";
}


+ 10
- 2
src/pages/PublicNotice/Details_Public/tabTableDetail/StatusHistoryTab.js Dosyayı Görüntüle

@@ -1,5 +1,6 @@
// material-ui
import * as React from 'react';
import { useTheme, useMediaQuery } from '@mui/material';
import {FiDataGrid} from "components/FiDataGrid";
import * as DateUtils from "utils/DateUtils"
import * as StatusUtils from "utils/statusUtils/PublicNoteStatusUtils";
@@ -9,7 +10,7 @@ import {GET_PUBLIC_NOTICE_APPLY_DETAIL_STATUS_HISTORY } from "utils/ApiPathConst
// ==============================|| EVENT TABLE ||============================== //

export default function StatusHistoryTab({appId, setCount}) {
const { useState, useEffect } = React;
const theme = useTheme();
const isMdOrLg = useMediaQuery(theme.breakpoints.up('md'));

@@ -21,6 +22,10 @@ export default function StatusHistoryTab({appId, setCount}) {
set_appId(appId);
}, []);

const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const columns = [
{
id: 'created',
@@ -28,6 +33,7 @@ export default function StatusHistoryTab({appId, setCount}) {
headerName: 'Date',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return DateUtils.datetimeStr(params?.value);
}
@@ -39,6 +45,7 @@ export default function StatusHistoryTab({appId, setCount}) {
headerName: 'Changed By',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
},
{
id: 'status',
@@ -46,8 +53,9 @@ export default function StatusHistoryTab({appId, setCount}) {
headerName: 'Status',
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return [StatusUtils.getStatusEng(params)]
return StatusUtils.getStatusEng(params);
},
},
];


+ 1
- 1
src/pages/PublicNotice/Details_Public/tabTableDetail/TabTable.js Dosyayı Görüntüle

@@ -43,7 +43,7 @@ const PublicNotice = ({ appId, proofCount, paymentCount, setProofCount, setPayme
<Grid item xs={12}>
<TabContext value={selectedTab}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<TabList onChange={handleChange} aria-label="lab API tabs example">
<TabList onChange={handleChange} aria-label={intl.formatMessage({ id: 'ariaRelatedRecords' })}>
<Tab
aria-label={intl.formatMessage({ id: 'proofRecord' })}
label={


+ 10
- 2
src/pages/PublicNotice/ListPanel/BaseGrid.js Dosyayı Görüntüle

@@ -28,6 +28,9 @@ export default function BaseGrid({setCount, url}) {
navigate('/publicNotice/'+ params.id);
};

const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const columns = [
{
@@ -36,8 +39,9 @@ export default function BaseGrid({setCount, url}) {
headerName: intl.formatMessage({id: 'applicationId'}),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return [params.row.appNo+getModeIntl(params,intl)]
return params.row.appNo + getModeIntl(params, intl);
},
},
{
@@ -46,6 +50,7 @@ export default function BaseGrid({setCount, url}) {
headerName: intl.formatMessage({id: 'submitDate'}),
width: isMdOrLg ? 'auto' : 300,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter:(params)=>{
return DateUtils.datetimeStr(params?.value);
}
@@ -57,6 +62,7 @@ export default function BaseGrid({setCount, url}) {
headerName: isORGLoggedIn()? intl.formatMessage({id: 'gazetteCount2_1'}) : intl.formatMessage({id: 'myRemarks'}),
width: isMdOrLg ? 'auto' : 400,
flex: isMdOrLg ? 3 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => (
isORGLoggedIn()?
isDummyLoggedIn()?
@@ -88,14 +94,16 @@ export default function BaseGrid({setCount, url}) {
headerName: intl.formatMessage({id: 'status'}),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return [getStatusIntl(params,intl)]
return getStatusIntl(params, intl);
},
},
{
field: 'actions',
headerName: '',
width: 160,
renderHeader: renderHeaderWithAria,
cellClassName: 'actions',
renderCell: (params) => {
return <Button aria-label={intl.formatMessage({id: 'viewDetail'})} onClick={handleDetailClick(params)}>


+ 40
- 17
src/pages/PublicNotice/ListPanel/PendingPaymentTab.js Dosyayı Görüntüle

@@ -81,6 +81,10 @@ export default function SubmittedTab({ setCount, url }) {
navigate('/publicNotice/' + params.id);
};

const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const handlePaymentBtn = () => {
let appIdList = [];
let paymentCheckList = [];
@@ -175,6 +179,7 @@ export default function SubmittedTab({ setCount, url }) {
headerName: intl.formatMessage({ id: 'applicationId' }),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
},
{
id: 'created',
@@ -182,6 +187,7 @@ export default function SubmittedTab({ setCount, url }) {
headerName: intl.formatMessage({ id: 'submitDate' }),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return DateUtils.datetimeStr(params.value);
}
@@ -192,6 +198,7 @@ export default function SubmittedTab({ setCount, url }) {
headerName: isORGLoggedIn() ? intl.formatMessage({ id: 'gazetteCount2_1' }) : intl.formatMessage({ id: 'myRemarks' }),
width: isMdOrLg ? 'auto' : 400,
flex: isMdOrLg ? 3 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => (
isORGLoggedIn() ?
isDummyLoggedIn()?
@@ -222,6 +229,7 @@ export default function SubmittedTab({ setCount, url }) {
headerName: intl.formatMessage({ id: 'price' }),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return FormatUtils.currencyFormat(params.row.fee)
},
@@ -230,6 +238,7 @@ export default function SubmittedTab({ setCount, url }) {
id: 'paymentMethodAndDeadLine',
field: 'paymentMethodAndDeadLine',
headerName: intl.formatMessage({ id: 'paymentMethodAndDeadLine' }),
renderHeader: renderHeaderWithAria,
width: isMdOrLg ? 'auto' : 250,
flex: isMdOrLg ? 2 : undefined,
renderCell: (params) => (
@@ -287,8 +296,9 @@ export default function SubmittedTab({ setCount, url }) {
headerName: intl.formatMessage({ id: 'status' }),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return [StatusUtils.getStatusIntl(params, intl)]
return StatusUtils.getStatusIntl(params, intl);
},
},
{
@@ -296,6 +306,7 @@ export default function SubmittedTab({ setCount, url }) {
type: 'actions',
headerName: '',
width: 150,
renderHeader: renderHeaderWithAria,
cellClassName: 'actions',
renderCell: (params) => {
return <Button aria-label={intl.formatMessage({ id: 'viewDetail' })} onClick={handleDetailClick(params)}>
@@ -313,23 +324,27 @@ export default function SubmittedTab({ setCount, url }) {
selectedRowItems.includes(row.id)
);
for (var i = 0; i < datas?.length; i++) {
content.push(<>
<Stack direction="row" justifyContent="space-between">
<Typography variant="h5">
<FormattedMessage id="applicationId" />: {datas[i].appNo}
</Typography>
({DateUtils.datetimeStr(datas[i].created)})
</Stack>
<FormattedMessage id="extraMark" />: {datas[i].remarks}
<br /><br />
</>);
content.push(
<React.Fragment key={datas[i].id}>
<Stack direction="row" justifyContent="space-between">
<Typography variant="h5">
<FormattedMessage id="applicationId" />: {datas[i].appNo}
</Typography>
({DateUtils.datetimeStr(datas[i].created)})
</Stack>
<FormattedMessage id="extraMark" />: {datas[i].remarks}
<br /><br />
</React.Fragment>
);

totalAmount += datas[i].fee;
}
content.push(<Typography variant="h5">
<FormattedMessage id="totalAmount" /> ($): {FormatUtils.currencyFormat(totalAmount)}
<br /><br />
</Typography>);
content.push(
<Typography key="payment-total" variant="h5">
<FormattedMessage id="totalAmount" /> ($): {FormatUtils.currencyFormat(totalAmount)}
<br /><br />
</Typography>
);
return content;
}

@@ -391,6 +406,11 @@ export default function SubmittedTab({ setCount, url }) {
id="careOfCombo"
value={selectedCareOf === null ? null : selectedCareOf}
options={careOfComboList}
getOptionLabel={(option) => {
if (option == null) return "";
if (typeof option === "string") return option;
return option.label != null ? String(option.label) : "";
}}
onChange={(event, newValue) => {
// console.log(newValue)
setSelectedCareOf(newValue);
@@ -400,7 +420,11 @@ export default function SubmittedTab({ setCount, url }) {
'& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
'& .MuiOutlinedInput-root': { height: 40 }
}}
renderInput={(params) => <TextField {...params} />}
renderInput={(params) => <TextField {...params} inputProps={{ ...params.inputProps, 'aria-label': intl.formatMessage({ id: 'careOf' }) }} />}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
/>
</Grid>
</Grid> : null
@@ -427,7 +451,6 @@ export default function SubmittedTab({ setCount, url }) {

<ThemeProvider theme={PNSPS_BUTTON_THEME}>
<Button
color="create"
variant="contained"
aria-label={intl.formatMessage({ id: 'payOnlineBtn' })}
onClick={() => { handlePaymentBtn() }}


+ 16
- 4
src/pages/PublicNotice/ListPanel/SearchPublicNoticeForm.js Dosyayı Görüntüle

@@ -138,7 +138,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
</Grid>

<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateFrom"
@@ -166,7 +166,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
</Grid>
<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
<DemoItem components={['DatePicker']}>
<DatePicker
id="dateTo"
@@ -234,7 +234,11 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
}
value={status}
// inputValue={status?.labelCht}
getOptionLabel={(option) => intl.formatMessage({id: option.label})}
getOptionLabel={(option) => {
if (option == null || option.label == null) return "";
const s = intl.formatMessage({ id: option.label });
return typeof s === "string" ? s : String(s ?? "");
}}
onChange={(event, newValue) => {
if(newValue ==null){
setStatus(localStorage.getItem('userData').creditor?ComboData.publicNoticeStatic_Creditor[0]:ComboData.publicNoticeStatic[0]);
@@ -256,6 +260,10 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
}}
/>
)}
clearText={intl.formatMessage({ id: "muiClear" })}
closeText={intl.formatMessage({ id: "muiClose" })}
openText={intl.formatMessage({ id: "muiOpen" })}
noOptionsText={intl.formatMessage({ id: "muiNoOptions" })}
// InputLabelProps={{
// shrink: true
// }}
@@ -276,7 +284,11 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) =>
}
value={status}
// inputValue={status?.labelCht}
getOptionLabel={(option) => intl.formatMessage({id: option.label})}
getOptionLabel={(option) => {
if (option == null || option.label == null) return "";
const s = intl.formatMessage({ id: option.label });
return typeof s === "string" ? s : String(s ?? "");
}}
onChange={(event, newValue) => {
console.log(newValue)
const findAllIndex = newValue.findIndex((ele) => {


+ 11
- 2
src/pages/PublicNotice/ListPanel/SearchPublicNoticeTable.js Dosyayı Görüntüle

@@ -35,6 +35,10 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
navigate('/publicNotice/' + params.id);
};

const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const columns = [
{
id: 'appNo',
@@ -42,8 +46,9 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: intl.formatMessage({ id: 'applicationId' }),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return [params.row.appNo+getModeIntl(params,intl)]
return params.row.appNo + getModeIntl(params, intl);
},
},
{
@@ -52,6 +57,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: intl.formatMessage({ id: 'submitDate' }),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return DateUtils.datetimeStr(params?.value);
}
@@ -88,6 +94,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: isORGLoggedIn() ? intl.formatMessage({ id: 'gazetteCount2_1' }) : intl.formatMessage({ id: 'myRemarks' }),
width: isMdOrLg ? 'auto' : 400,
flex: isMdOrLg ? 3 : undefined,
renderHeader: renderHeaderWithAria,
renderCell: (params) => (
isORGLoggedIn() ?
isDummyLoggedIn()?
@@ -117,8 +124,9 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
field: 'status',
headerName: intl.formatMessage({ id: 'status' }),
width: 200,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return [StatusUtils.getStatusIntl(params, intl)]
return StatusUtils.getStatusIntl(params, intl);
},
},
{
@@ -126,6 +134,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
type: 'actions',
headerName: '',
width: 150,
renderHeader: renderHeaderWithAria,
cellClassName: 'actions',
renderCell: (params) => {
return <Button onClick={handleDetailClick(params)}


+ 11
- 6
src/pages/PublicNotice/ListPanel/index.js Dosyayı Görüntüle

@@ -31,11 +31,12 @@ import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
import { PNSPS_LONG_BUTTON_THEME } from "../../../themes/buttonConst";
import { ThemeProvider } from "@emotion/react";
import { FormattedMessage, useIntl } from "react-intl";


import usePageTitle from 'components/usePageTitle';
// ==============================|| DASHBOARD - DEFAULT ||============================== //

const PublicNotice = () => {
usePageTitle("myPublicNotice");
const [submittedCount, setSubmittedCount] = useState(0);
const [pendingPaymentCount, setPendingPaymentCount] = useState(0);
const [pendingPublishCount, setPendingPublishCount] = useState(0);
@@ -113,7 +114,7 @@ const PublicNotice = () => {
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' } }}>
<Typography component="h1" ml={15} color='#FFF' variant="h4" sx={{ display: { xs: 'none', sm: 'none', md: 'block' } }}>
<FormattedMessage id="myPublicNotice" />
</Typography>
</Stack>
@@ -123,7 +124,11 @@ const PublicNotice = () => {
<Stack direction="row" justifyContent="flex-end" alignItems="center">
<ThemeProvider theme={PNSPS_LONG_BUTTON_THEME}>
<Box sx={{ mr: { md: "47px" } }}>
<Button aria-label={intl.formatMessage({ id: 'applyPublicNotice' })} variant="contained" onClick={() => { onBtnClick() }}>
<Button
aria-label={intl.formatMessage({ id: 'applyPublicNotice' })}
variant="contained"
onClick={() => { onBtnClick() }}
>
<FormattedMessage id="applyPublicNotice" />
</Button>
</Box>
@@ -137,7 +142,7 @@ const PublicNotice = () => {
<Grid item xs={12} sm={12} md={12} lg={12} sx={{ height: '100%', maxWidth: '100%', width: "-webkit-fill-available", backgroundColor: "#fff", mt: 3, mr: { xs: 1, md: 3 }, ml: { xs: 1, md: 3 }, mb: 3, ..._sx }}>
<TabContext value={selectedTab}>
<Box sx={{ borderBottom: 1, borderColor: 'divider', overflowX: 'auto', overflowY: 'auto' }}>
<TabList variant="scrollable" onChange={handleChange} aria-label="lab API tabs example" sx={{ display: 'flex', flexDirection: 'row' }}>
<TabList variant="scrollable" onChange={handleChange} aria-label={intl.formatMessage({ id: 'ariaRelatedRecords' })} sx={{ display: 'flex', flexDirection: 'row' }}>
<Tab aria-label={intl.formatMessage({ id: 'processing' })} label={intl.formatMessage({ id: 'processing' }) + " (" + submittedCount + ")"} value="1" />
<Tab aria-label={intl.formatMessage({ id: 'pendingPublish' })} label={intl.formatMessage({ id: 'pendingPublish' }) + " (" + pendingPublishCount + ")"} value="3" />
<Tab aria-label={intl.formatMessage({ id: 'pendingPayment' })} label={intl.formatMessage({ id: 'pendingPayment' }) + " (" + pendingPaymentCount + ")"} value="4" />
@@ -171,7 +176,7 @@ const PublicNotice = () => {
<Grid item xs={12} sx={{ minHeight: '80vh', height: "100%", maxHeight: '300vh', maxWidth: '95%', width: "-webkit-fill-available", backgroundColor: "#fff", mt: 3, mr: { xs: 1, md: 3 }, ml: { xs: 1, md: 3 }, mb: 3, ..._sx }}>
<TabContext value={selectedTab}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<TabList variant="scrollable" onChange={handleChange} aria-label="lab API tabs example">
<TabList variant="scrollable" onChange={handleChange} aria-label={intl.formatMessage({ id: 'ariaApplicationGroup' })}>
<Tab aria-label={intl.formatMessage({ id: 'processing' })} label={intl.formatMessage({ id: 'processing' }) + " (" + submittedCount + ")"} value="1" />
<Tab aria-label={intl.formatMessage({ id: 'pendingPayment' })} label={intl.formatMessage({ id: 'pendingPayment' }) + " (" + pendingPaymentCount + ")"} value="3" />
<Tab aria-label={intl.formatMessage({ id: 'pendingPublish' })} label={intl.formatMessage({ id: 'pendingPublish' }) + " (" + pendingPublishCount + ")"} value="4" />


+ 14
- 3
src/pages/PublicNotice/Search_GLD/DataGrid.js Dosyayı Görüntüle

@@ -53,6 +53,10 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
return groupNo
}

const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const columns = [
{
field: 'actions',
@@ -60,6 +64,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
sortable: false,
width: 150,
cellClassName: 'actions',
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return clickableLink('/application/' + params.id, params.row.appNo);
},
@@ -70,8 +75,9 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: 'Mode',
sortable: false,
width: 100,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return [StatusUtils.getModeEng(params)]
return StatusUtils.getModeEng(params);
},
},
{
@@ -80,8 +86,9 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: 'Status',
sortable: false,
width: 240,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return [StatusUtils.getStatusEng(params)]
return StatusUtils.getStatusEng(params);
},
},
{
@@ -90,8 +97,9 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: 'With Proof',
sortable: false,
width: 120,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return [params.row.proofId != null ? "Yes" : ""]
return params.row.proofId != null ? "Yes" : "";
},
},
{
@@ -101,6 +109,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
sortable: false,
flex: 1,
minWidth: 200,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return DateUtils.datetimeStr(params?.value);
}
@@ -112,6 +121,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
sortable: false,
minWidth: 250,
flex: 2,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
let company = params.row.enCompanyName != null ? params.row.enCompanyName : params.row.chCompanyName;
company = company != null ? company : "";
@@ -131,6 +141,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
sortable: false,
flex: 1.5,
minWidth: 350,
renderHeader: renderHeaderWithAria,
renderCell: (params) => (
<div>
{genIssueNo(params)}


+ 4
- 4
src/pages/PublicNotice/Search_GLD/SearchForm.js Dosyayı Görüntüle

@@ -279,7 +279,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss
setSelectedStatus(newValue);
}
}}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
sx={{
'& .MuiInputBase-root': { alignItems: 'center' },
'& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
@@ -317,7 +317,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss
setSelectedLabelsString(selectedLabelsString);
}
}}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
renderInput={(params) => (
<TextField
{...params}
@@ -419,7 +419,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss
options={ComboData.groupTitle}
value={groupSelected}
inputValue={(groupSelected?.label) ? groupSelected?.label : ""}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
onChange={(event, newValue) => {
setGroupSelected(newValue);
}}
@@ -470,7 +470,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss
'& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
'& .MuiOutlinedInput-root': { height: 40 }
}}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
renderInput={(params) => (
<TextField
{...params}


+ 10
- 0
src/pages/PublicNotice/Search_Mark_As_Paid_GLD/DataGrid.js Dosyayı Görüntüle

@@ -115,6 +115,10 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea

};

const renderHeaderWithAria = (params) => (
<span aria-label={params.colDef.headerName}>{params.colDef.headerName}</span>
);

const columns = [
{
field: 'actions',
@@ -122,6 +126,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
sortable: false,
width: 150,
cellClassName: 'actions',
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
return clickableLink('/application/' + params.id, params.row.appNo);
},
@@ -132,6 +137,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: 'Customer Name',
flex: 1,
minWidth: 50,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
let company = params.row.enCompanyName != null ? params.row.enCompanyName : params.row.chCompanyName;
company = company != null ? company : "";
@@ -150,6 +156,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
sortable: false,
flex: 1.5,
minWidth: 350,
renderHeader: renderHeaderWithAria,
renderCell: (params) => (
<div>
{genIssueNo(params)}
@@ -165,6 +172,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
sortable: false,
minWidth: 250,
flex: 2,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
let paymentMethod = params.row.paymentMethod!=null?intl.formatMessage({ id: utils.getPaymentMethod(params.row.paymentMethod)}):""
return (<>
@@ -178,6 +186,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: 'Amount($)',
flex: 1,
minWidth: 100,
renderHeader: renderHeaderWithAria,
valueGetter: (params) => {
return FormatUtils.currencyFormat(params?.value);
}
@@ -188,6 +197,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
headerName: 'Remarks',
flex: 2,
minWidth: 200,
renderHeader: renderHeaderWithAria,
renderCell: (params) => {
const handleBlur = (event) => {
const newValue = event.target.value;


+ 2
- 2
src/pages/PublicNotice/Search_Mark_As_Paid_GLD/SearchForm.js Dosyayı Görüntüle

@@ -266,7 +266,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss
setSelectedStatus(newValue);
}
}}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
sx={{
'& .MuiInputBase-root': { alignItems: 'center' },
'& .MuiAutocomplete-endAdornment': { top: '50%', transform: 'translateY(-50%)' },
@@ -304,7 +304,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss
setSelectedLabelsString(selectedLabelsString);
}
}}
getOptionLabel={(option) => option.label}
getOptionLabel={(option) => (option?.label != null ? String(option.label) : "")}
renderInput={(params) => (
<TextField
{...params}


Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor

Yükleniyor…
İptal
Kaydet