public and department staff can fill the form for green committee and check the status
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1871 lines
67 KiB

4 months ago
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
4 months ago
4 months ago
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
4 months ago
4 months ago
​
​
​
​
4 months ago
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
4 months ago
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
4 months ago
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
4 months ago
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
4 months ago
​
​
4 months ago
​
​
4 months ago
​
​
​
​
​
4 months ago
4 months ago
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
4 months ago
​
4 months ago
4 months ago
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
4 months ago
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
4 months ago
​
​
​
​
​
​
4 months ago
​
​
4 months ago
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
4 months ago
4 months ago
  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>GCC Green Committee</title>
  6. <meta name="description" content="">
  7. <meta name="keywords" content="">
  8. <meta name="viewport" content="width=device-width, initial-scale=1">
  9. <base th:href="${baseURL}" />
  10. <link rel="icon" th:href="@{images/favicon.ico}" type="image/x-icon" />
  11. <link href="https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,600,700,800" rel="stylesheet">
  12. <link rel="stylesheet" type="text/css" th:href="@{assets/node_modules/bootstrap/dist/css/bootstrap.min.css}">
  13. <link rel="stylesheet" type="text/css" th:href="@{assets/node_modules/select2/dist/css/select2.min.css}">
  14. <link rel="stylesheet" type="text/css" th:href="@{assets/node_modules/sweetalert2/sweetalert2.min.css}">
  15. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
  16. <style>
  17. /* Header Styling */
  18. .header {
  19. background-color: #1d495a;
  20. padding: 10px 20px;
  21. color: white;
  22. font-family: Arial, sans-serif;
  23. }
  24. .header .logo img {
  25. height: 50px;
  26. }
  27. .header .center-text {
  28. text-align: center;
  29. font-size: 24px;
  30. }
  31. .header .menu-btn {
  32. background-color: transparent;
  33. border: none;
  34. font-size: 24px;
  35. color: white;
  36. }
  37. .header .menu-btn:hover {
  38. color: #ccc;
  39. }
  40. /* Menu Dropdown */
  41. .menu-dropdown {
  42. position: absolute;
  43. top: 60px;
  44. right: 20px;
  45. background-color: #1d495a;
  46. padding: 10px;
  47. display: none;
  48. flex-direction: column;
  49. z-index: 1000;
  50. /* Add z-index to bring the menu above other elements */
  51. }
  52. .menu-dropdown a {
  53. color: white;
  54. margin-bottom: 5px;
  55. text-decoration: none;
  56. }
  57. .menu-dropdown a:hover {
  58. text-decoration: underline;
  59. }
  60. /* Mobile Specific Styling */
  61. @media (max-width: 768px) {
  62. .header {
  63. display: flex;
  64. justify-content: space-between;
  65. align-items: center;
  66. }
  67. .center-text {
  68. font-size: 18px !important;
  69. flex-grow: 1;
  70. text-align: center;
  71. }
  72. .menu-dropdown {
  73. right: 0;
  74. left: 0;
  75. z-index: 1000;
  76. /* Add z-index to bring the menu above other elements */
  77. }
  78. }
  79. /*css for map in step2*/
  80. #googleMap {
  81. height: 300px;
  82. width: 100%;
  83. position: relative;
  84. overflow: hidden;
  85. max-width: 100%;
  86. }
  87. /* #pac-input {
  88. position: absolute;
  89. top: 10px;
  90. left: 50%;
  91. transform: translateX(-50%);
  92. width: 300px;
  93. z-index: 5;
  94. padding: 10px;
  95. border: 1px solid #ccc;
  96. background-color: white;
  97. border-radius: 4px;
  98. }
  99. #search-container {
  100. position: absolute;
  101. top: 10px;
  102. left: 50%;
  103. transform: translateX(-50%);
  104. z-index: 1000;
  105. width: 500px;
  106. box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
  107. background-color: white;
  108. border-radius: 4px;
  109. padding: 0;
  110. } */
  111. #pac-input {
  112. width: 100%;
  113. padding: 10px;
  114. border: 1px solid #ccc;
  115. border-radius: 4px;
  116. font-size: 15px;
  117. box-sizing: border-box;
  118. }
  119. #search-box {
  120. width: 100%;
  121. /* Ensures the input takes up the entire width of the container */
  122. padding: 5px;
  123. font-size: 16px;
  124. border: 1px solid #ccc;
  125. border-radius: 4px;
  126. /* Rounded corners matching the container */
  127. box-sizing: border-box;
  128. /* Makes sure padding is considered in width */
  129. }
  130. /* #suggestions {
  131. border: 1px solid #ccc;
  132. border-radius: 4px;
  133. max-height: 200px;
  134. overflow-y: auto;
  135. margin-top: 5px;
  136. background-color: white;
  137. display: none;
  138. width: 100%;
  139. box-sizing: border-box;
  140. }
  141. #suggestions ul {
  142. list-style: none;
  143. padding: 0;
  144. margin: 0;
  145. }
  146. #suggestions ul li {
  147. padding: 5px;
  148. cursor: pointer;
  149. }
  150. #suggestions ul li:hover {
  151. background-color: #f0f0f0;
  152. } */
  153. #suggestions {
  154. width: 100%;
  155. display: none;
  156. background: #fff;
  157. border: 1px solid #ccc;
  158. border-top: none;
  159. max-height: 220px;
  160. overflow-y: auto;
  161. box-shadow: 0 2px 8px rgba(0, 0, 0, .25);
  162. }
  163. #suggestions ul {
  164. margin: 0;
  165. padding: 0;
  166. list-style: none;
  167. }
  168. #suggestions li {
  169. padding: 10px 12px;
  170. cursor: pointer;
  171. border-bottom: 1px solid #eee;
  172. }
  173. #suggestions li:hover {
  174. background: #f5f5f5;
  175. }
  176. #search-container {
  177. position: absolute;
  178. top: 10px;
  179. left: 50%;
  180. transform: translateX(-50%);
  181. width: 420px;
  182. z-index: 1000;
  183. }
  184. .multi-select-dropdown {
  185. position: relative;
  186. }
  187. .dropdown-checkbox-menu {
  188. position: absolute;
  189. background: #fff;
  190. border: 1px solid #ccc;
  191. width: 100%;
  192. max-height: 200px;
  193. overflow-y: auto;
  194. display: none;
  195. z-index: 999;
  196. padding: 10px;
  197. border-radius: 5px;
  198. }
  199. .otp-input-box {
  200. /*display: flex;
  201. justify-content: space-between;*/
  202. width: 100%;
  203. }
  204. .otp-input {
  205. width: 30px;
  206. height: 30px;
  207. border: 1px solid #ccc;
  208. border-radius: 5px;
  209. text-align: center;
  210. font-size: 16px;
  211. margin-right: 10px;
  212. }
  213. /* Better card look */
  214. .card {
  215. border-radius: 12px;
  216. border: none;
  217. box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  218. }
  219. /* Section title */
  220. .section-header h5 {
  221. font-weight: 600;
  222. letter-spacing: 1px;
  223. padding-bottom: 10px;
  224. border-bottom: 2px solid #1d495a;
  225. display: inline-block;
  226. }
  227. /* Form labels */
  228. .form-label {
  229. font-weight: 600;
  230. color: #1d495a;
  231. }
  232. /* Form inputs */
  233. .form-control {
  234. height: 45px;
  235. border-radius: 7px !important;
  236. border: 1px solid #c7c7c7;
  237. transition: 0.2s ease-in-out;
  238. }
  239. .form-control:focus {
  240. border-color: #1d495a;
  241. box-shadow: 0 0 5px rgba(29, 73, 90, 0.3);
  242. }
  243. /* Textarea styling */
  244. textarea.form-control {
  245. min-height: 40px;
  246. resize: vertical;
  247. }
  248. /* OTP button alignment */
  249. #sendOtpButton {
  250. width: 100%;
  251. }
  252. /* Map container rounded & shadow */
  253. #mapContainer {
  254. border-radius: 10px;
  255. overflow: hidden;
  256. box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
  257. }
  258. /* Search bar inside map */
  259. /* #pac-input {
  260. width: 80% !important;
  261. max-width: 350px;
  262. border-radius: 8px !important;
  263. } */
  264. /* Multi-select dropdown box */
  265. .multi-select-dropdown .form-control {
  266. background: #f8f9fa;
  267. cursor: pointer;
  268. }
  269. /* Dropdown list */
  270. .dropdown-checkbox-menu {
  271. border-radius: 8px;
  272. border-color: #aaa;
  273. background: #fefefe;
  274. box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
  275. }
  276. /* File inputs */
  277. #img_container input {
  278. height: 53px !important;
  279. padding: 10px;
  280. border-radius: 6px;
  281. }
  282. /* Submit button */
  283. #submitBtn {
  284. width: 180px;
  285. height: 45px;
  286. font-size: 16px;
  287. border-radius: 8px;
  288. }
  289. /* Back button */
  290. #backBtn {
  291. border-radius: 8px;
  292. padding: 10px 25px;
  293. }
  294. /* Improved spacing on mobile */
  295. @media (max-width: 768px) {
  296. .row {
  297. row-gap: 15px;
  298. }
  299. #sendOtpButton {
  300. margin-top: 10px !important;
  301. }
  302. }
  303. </style>
  304. </head>
  305. <body style="background-color: #f1f3f4;">
  306. <!-- Header Start-->
  307. <header>
  308. <div class="header d-flex justify-content-between align-items-center">
  309. <!-- Left: Logo -->
  310. <div class="logo">
  311. <img src="https://gccservices.in/gcc/assets/images/logo.png" alt="Logo">
  312. </div>
  313. <!-- Center: Text -->
  314. <div class="center-text">
  315. GREATER CHENNAI CORPORATION
  316. </div>
  317. <!-- Right: Button for Menu -->
  318. <div class="menu">
  319. <button class="menu-btn" onclick="toggleMenu()">
  320. &#9776; <!-- Unicode for hamburger menu icon -->
  321. </button>
  322. </div>
  323. </div>
  324. <!-- Dropdown Menu -->
  325. <div class="menu-dropdown" id="menuDropdown">
  326. <a href="https://chennaicorporation.gov.in/gcc/">Home</a>
  327. <a href="https://chennaicorporation.gov.in/gcc/about-GCC/">About GCC</a>
  328. <a href="https://chennaicorporation.gov.in/gcc/who-is-who/index_data.jsp">Who's Who</a>
  329. <a href="https://chennaicorporation.gov.in/gcc/council/about-council/">Council</a>
  330. <a href="https://chennaicorporation.gov.in/gcc/tender/">Tender</a>
  331. <a href="https://chennaicorporation.gov.in/gcc/department/">Departments</a>
  332. <a href="https://chennaicorporation.gov.in/gcc/online-services/">Online Services</a>
  333. <a href="https://gccservices.in/gcc/login">Official Login</a>
  334. </div>
  335. </header>
  336. <!-- Header End-->
  337. <main class="container mt-4">
  338. <div class="p-4">
  339. <form id="publicform" enctype="multipart/form-data">
  340. <div class="section-header text-center">
  341. <h5>GREEN COMMITTEE CITIZEN FORM (PUBLIC)</h5>
  342. </div>
  343. <div class="row mb-3 mt-2">
  344. <div class="col-md-4">
  345. <label class="form-label">Petitioner Name<span class="text-danger">*</span></label>
  346. <input type="text" class="form-control" id="pname" name="name"
  347. oninput="this.value = this.value.replace(/[^a-zA-Z\s]/g, '')" placeholder="Enter Name"
  348. required>
  349. </div>
  350. <div class="col-md-3">
  351. <label class="form-label">Mobile Number<span class="text-danger">*</span></label>
  352. <input type="text" class="form-control" id="mobile_no" name="mobile_no"
  353. oninput="validatePhoneNumber(this)" placeholder="Enter Mobile Number" required>
  354. </div>
  355. <div class="col-md-2" id="otpbeforeverified">
  356. <button type="button" class="btn btn-primary" id="sendOtpButton" style="margin-top: 32px;">Send
  357. OTP</button>
  358. </div>
  359. <div class="col-md-2" id="otpafterverified" style="display: none;">
  360. <i class="fa-solid fa-circle-check"
  361. style="margin-top: 40px;font-size: x-large;color: green;"></i>
  362. </div>
  363. </div>
  364. <div class="row mb-4">
  365. <div class="col-md-4">
  366. <label class="form-label">Gender<span class="text-danger">*</span></label><br>
  367. <input type="radio" name="gender" value="M" required="required"> Male
  368. <input type="radio" name="gender" value="F" class="ms-3 ml-3"> Female
  369. <input type="radio" name="gender" value="T" class="ms-3 ml-3"> Transgender
  370. </div>
  371. <!--<div class="col-md-8">
  372. <label class="form-label">Tree Land Location (Also click the street in Map)<span
  373. class="text-danger">*</span></label>
  374. <textarea class="form-control" id="address" name="address" maxlength="255"
  375. placeholder="Type Tree Address Here" required></textarea>
  376. </div>-->
  377. </div>
  378. <!-- <div class="row mb-3">
  379. <div class="col-md-6">
  380. <label class="form-label">Gender<span class="text-danger">*</span></label><br>
  381. <input type="radio" name="gender" value="M" required="required"> Male
  382. <input type="radio" name="gender" value="F" class="ms-3 ml-4"> Female
  383. <input type="radio" name="gender" value="T" class="ms-3 ml-4"> Transgender
  384. </div>
  385. </div> -->
  386. <!-- <div class="row mb-3">
  387. <div class="col-md-12">
  388. <label class="form-label">Tree Land Location (Also click the street in Map)<span class="text-danger">*</span></label>
  389. <textarea class="form-control" id="address" name="address" maxlength="255" placeholder="Type Tree Address Here" required ></textarea>
  390. </div>
  391. </div> -->
  392. <div id="mapContainer" style="position: relative; height: 300px;">
  393. <div id="search-container">
  394. <input id="pac-input" class="controls" type="text" placeholder="Search location - please enter minimum of 5 characters">
  395. <!-- <input type="text" id="search-box" placeholder="Search for a location..."> -->
  396. <div id="suggestions"></div>
  397. </div>
  398. <div id="googleMap" style="height: 100%; width: 100%;"></div>
  399. </div>
  400. <div class="row mb-3 mt-4" style="row-gap:10px;">
  401. <div class="col-md-3">
  402. <label for="latitude">Latitude<span class="text-danger">*</span></label>
  403. <input type="text" class="form-control" id="latitude" name="latitude" readonly>
  404. </div>
  405. <div class="col-md-3">
  406. <label for="longitude">Longitude<span class="text-danger">*</span></label>
  407. <input type="text" class="form-control" id="longitude" name="longitude" readonly>
  408. </div>
  409. <div class="col-md-6">
  410. <label for="streetName">Street<span class="text-danger">*</span></label>
  411. <select id="streetName" name="streetName" class="form-control" required>
  412. <option value="">Select Street</option>
  413. </select>
  414. </div>
  415. <!-- <div class="col-md-3">
  416. <label for="zone">Zone<span class="text-danger">*</span></label>
  417. <input type="text" class="form-control" id="zone" name="zone" required readonly>
  418. </div>
  419. <div class="col-md-3">
  420. <label for="ward">Ward<span class="text-danger">*</span></label>
  421. <input type="text" class="form-control" id="ward" name="ward" required readonly>
  422. </div>-->
  423. </div>
  424. <!-- <div class="row mb-3">
  425. <div class="col-md-4">
  426. <label class="form-label">Details of Complaint<span class="text-danger">*</span></label>
  427. <div class="multi-select-dropdown">
  428. <div id="dropdownToggle" class="form-control" style="cursor:pointer;" required>
  429. Select Options
  430. </div>
  431. <small class="text-danger">
  432. <strong>Note:</strong> Only one complaint can be selected.
  433. </small>
  434. <div id="compnature_checkbox_list" class="dropdown-checkbox-menu"></div>
  435. </div>
  436. </div>
  437. </div>-->
  438. <div class="row mb-3">
  439. <input type="hidden" id="streetId" name="streetId">
  440. <!-- <div class="col-md-3">
  441. <label for="streetId">Street Id</label>
  442. <input type="text" class="form-control" id="streetId" readonly>
  443. </div>-->
  444. <div class="col-md-3">
  445. <label for="zone">Zone<span class="text-danger">*</span></label>
  446. <input type="text" class="form-control" id="zone" name="zone" readonly>
  447. </div>
  448. <div class="col-md-3">
  449. <label for="ward">Ward<span class="text-danger">*</span></label>
  450. <input type="text" class="form-control" id="ward" name="ward" readonly>
  451. </div>
  452. </div>
  453. <div class="row mb-3">
  454. <!-- Left Side -->
  455. <div class="col-md-4">
  456. <label class="form-label">
  457. Request Type<span class="text-danger">*</span>
  458. </label>
  459. <select id="complaintDropdown" class="form-control" required>
  460. <option value="">Select Complaint</option>
  461. </select>
  462. <div class="text-danger mt-2">
  463. <strong>Note:</strong> Only one complaint can be selected.
  464. </div>
  465. <!-- <div class="multi-select-dropdown">
  466. <div id="dropdownToggle" class="form-control" style="cursor:pointer;" required>
  467. Select Options
  468. </div>
  469. <div class="text-danger mt-2">
  470. <strong>Note:</strong> Only one complaint can be selected.
  471. </div>-->
  472. <!-- <small class="text-danger">
  473. <strong>Note:</strong> Only one complaint can be selected.
  474. </small>-->
  475. <!--- <div id="compnature_checkbox_list" class="dropdown-checkbox-menu"></div>
  476. </div>-->
  477. </div>
  478. <!-- Right Side -->
  479. <!--<div class="col-md-8">
  480. <div class="alert alert-info mb-0 py-2">
  481. <strong>Instructions:</strong><br>
  482. <strong>NOTE: </strong>For tree pruning complaints, please raise your complaint through the
  483. PGR portal
  484. <strong>Complaint Type:</strong> Park and Playground
  485. <br>
  486. <strong>Complaint Sub-Type:</strong> Obstruction of Trees
  487. <br>
  488. <a href="https://gccservices.in/pgr/registercomplaints" target="_blank">
  489. Click here to raise the complaint
  490. </a>
  491. </div>
  492. </div>-->
  493. </div>
  494. <!-- Dynamic input rows -->
  495. <div id="naturecontainer"></div>
  496. <div class="row mb-3">
  497. <div class="col-md-6">
  498. <label for="address">Location of Tree<span class="text-danger">*</span></label>
  499. <!-- <input type="text" class="form-control" id="address" name="address" placeholder="Enter Address"
  500. required>-->
  501. <textarea class="form-control" id="address" name="address" placeholder="Type Tree Address Here"
  502. required></textarea>
  503. </div>
  504. </div>
  505. <div class="row mb-3">
  506. <div class="col-md-12">
  507. <label class="form-label">Remarks<span class="text-danger">*</span></label>
  508. <textarea class="form-control" id="remarks" name="remarks" maxlength="255"
  509. placeholder="Enter Remarks" required></textarea>
  510. </div>
  511. </div>
  512. <div class="row mb-3" id="img_container">
  513. <div class="col-md-6">
  514. <label class="form-label">Upload Image 1 (jpg/jpeg)<span class="text-danger">*</span></label>
  515. <input type="file" class="form-control" id="c1image" accept=".jpg,.jpeg," name="c1image"
  516. required="required">
  517. </div>
  518. <div class="col-md-6">
  519. <label class="form-label">Upload Image 2 (jpg/jpeg)<span class="text-danger">*</span></label>
  520. <input type="file" class="form-control" id="c2image" accept=".jpg,.jpeg," name="c2image"
  521. required="required">
  522. </div>
  523. </div>
  524. <span>OTP validation is mandatory for submitting the form.<span class="text-danger">*</span></span>
  525. <div class="text-center mt-4">
  526. <button type="submit" class="btn btn-success" name="submitBtn" id="submitBtn"
  527. disabled>Submit</button>
  528. </div>
  529. </form>
  530. <div class="mt-4">
  531. <button class="btn btn-secondary" id="backBtn">Back</button>
  532. </div>
  533. </div>
  534. </main>
  535. <div class="modal fade" id="otpForm" tabindex="-1" role="dialog" aria-labelledby="otpFormLabel" aria-hidden="true">
  536. <div class="modal-dialog" role="document">
  537. <div class="modal-content">
  538. <form action="#" th:action="@{/otpForm}" th:object="${otpForm}" method="post"
  539. onsubmit="return verifyOtp();">
  540. <div class="modal-header">
  541. <h6 class="modal-title m-0" id="exampleModalDefaultLabel">OTP Login</h6>
  542. <button type="button" class="close" data-dismiss="modal" aria-label="Close"
  543. style="color:black;border: white;background-color: white;">
  544. <span aria-hidden="true" style="font-size: larger;">&times;</span>
  545. </button>
  546. </div><!--end modal-header-->
  547. <div class="modal-body">
  548. <div class="row ">
  549. <div class="mb-3" style="text-align: center;">
  550. <img th:src="@{images/otp.png}" width="50%" alt="Mobileotp">
  551. </div>
  552. </div><!--end row-->
  553. <div class="row d-flex justify-content-center align-items-center">
  554. <div class="mb-0">
  555. <h4>OTP Verification</h4>
  556. <p class="text-mute">Enter the OTP sent to <b class="text-info" id="mobilenotxt"></b>
  557. </p>
  558. <p class="text-danger text-center" id="otperror"></p>
  559. </div>
  560. </div><!--end row-->
  561. <div class="row d-flex justify-content-center align-items-center">
  562. <div class="mb-3 ">
  563. <div class="otp-input-box">
  564. <input type="text" maxlength="1" class="otp-input" id="otp1" required />
  565. <input type="text" maxlength="1" class="otp-input" id="otp2" required />
  566. <input type="text" maxlength="1" class="otp-input" id="otp3" required />
  567. <input type="text" maxlength="1" class="otp-input" id="otp4" required />
  568. <input type="text" maxlength="1" class="otp-input" id="otp5" required />
  569. </div>
  570. </div>
  571. </div><!--end row-->
  572. <div class="row d-flex justify-content-center align-items-center">
  573. <div class="mb-3">
  574. <div id="resend-containers">
  575. <p class="mb-0">Didn't receive OTP?</p>
  576. <p class="mb-0 mt-2 text-info text-center" id="resend-link"></p>
  577. </div>
  578. </div>
  579. </div><!--end row-->
  580. </div><!--end modal-body-->
  581. <div class="modal-footer">
  582. <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
  583. <button type="submit" class="btn btn-primary" id="but">Verify OTP</button>
  584. </div><!--end modal-footer-->
  585. </form>
  586. </div><!--end modal-content-->
  587. </div><!--end modal-dialog-->
  588. </div>
  589. <div id="pageLoader"
  590. style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;">
  591. <div style="position: relative; top: 50%; transform: translateY(-50%);">
  592. <div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;">
  593. <span class="sr-only">Loading...</span>
  594. </div>
  595. <!-- Add the 'Please wait' text below the spinner -->
  596. <p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p>
  597. </div>
  598. </div>
  599. <script type="text/javascript" th:src="@{assets/node_modules/jquery/dist/jquery.min.js}"></script>
  600. <script type="text/javascript" th:src="@{assets/node_modules/bootstrap/dist/js/bootstrap.min.js}"></script>
  601. <script type="text/javascript" th:src="@{assets/node_modules/select2/dist/js/select2.min.js}"></script>
  602. <script type="text/javascript" th:src="@{assets/node_modules/sweetalert2/sweetalert2.min.js}"></script>
  603. <script sync defer
  604. src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCi7N6uW5MZaSkd50Kzw7ax2GkMN1vjE-E&callback=myMap&libraries=places">
  605. </script>
  606. <script type="text/javascript">
  607. let mobile_valid = false;
  608. $(document).ready(function () {
  609. /*let checkboxList = $("#compnature_checkbox_list");
  610. let natureContainer = $("#naturecontainer");
  611. // Toggle dropdown on click
  612. $("#dropdownToggle").on("click", function () {
  613. checkboxList.toggle();
  614. });
  615. // Close dropdown when clicking outside
  616. $(document).click(function (e) {
  617. if (!$(e.target).closest(".multi-select-dropdown").length) {
  618. checkboxList.hide();
  619. }
  620. });*/
  621. // Fetch API data
  622. fetch('/greencommittee/api/getcompnatureforpublic')
  623. .then(res => res.json())
  624. .then(result => {
  625. if (result.status !== "success") return;
  626. let list = result.data;
  627. let dropdown = $("#complaintDropdown");
  628. list.forEach(function (d) {
  629. dropdown.append(
  630. `<option value="${d.id}" data-name="${d.name}">
  631. ${d.name}
  632. </option>`
  633. );
  634. });
  635. /*list.forEach(d => {
  636. checkboxList.append(`
  637. <div class="form-check">
  638. <input type="checkbox"
  639. class="form-check-input nature-check"
  640. id="nature_${d.id}"
  641. data-id="${d.id}"
  642. data-name="${d.name}">
  643. <label class="form-check-label" for="nature_${d.id}">
  644. ${d.name}
  645. </label>
  646. </div>
  647. `);
  648. });*/
  649. });
  650. // Handle checkbox selection
  651. /*$(document).on("change", ".nature-check", function () {
  652. let id = $(this).data("id");
  653. let name = $(this).data("name");
  654. updateDropdownLabel(); // update selected names on the dropdown
  655. // If checked → add column box
  656. if ($(this).is(":checked")) {
  657. // Create the row ONCE
  658. if ($("#treeRow").length === 0) {
  659. $("#naturecontainer").append(`<div class="row" id="treeRow"></div>`);
  660. }
  661. let html = `
  662. <div class="col-md-4 mb-3 tree-input-box" id="col_${id}">
  663. <label class="form-label">No. of Trees - ${name}<span class="text-danger">*</span></label>
  664. <input type="number" min="0" class="form-control"
  665. id="trees_${id}" placeholder="Enter count" required="required">
  666. </div>
  667. `;
  668. $("#treeRow").append(html);
  669. }
  670. else {
  671. // Remove column on uncheck
  672. $("#col_" + id).remove();
  673. // If all unchecked → remove row
  674. if ($(".tree-input-box").length === 0) {
  675. $("#treeRow").remove();
  676. }
  677. }
  678. });*/
  679. $(document).on("change", "#complaintDropdown", function () {
  680. $("#treeRow").remove();
  681. let id = $(this).val();
  682. let name = $("#complaintDropdown option:selected").data("name");
  683. if (!name) {
  684. // Nothing selected
  685. $("#c2image").closest(".col-md-6").show();
  686. $("#c2image").prop("required", true);
  687. $("#address").closest(".col-md-6").hide();
  688. $("#address").prop("required", false).val("");
  689. } else if (name.toLowerCase() === "pruning") {
  690. // Pruning selected
  691. $("#c2image").closest(".col-md-6").hide();
  692. $("#c2image").prop("required", false).val("");
  693. $("#address").closest(".col-md-6").hide();
  694. $("#address").prop("required", false).val("");
  695. } else {
  696. // Any complaint other than pruning
  697. $("#c2image").closest(".col-md-6").show();
  698. $("#c2image").prop("required", true);
  699. $("#address").closest(".col-md-6").show();
  700. $("#address").prop("required", true);
  701. }
  702. /* if (name && name.toLowerCase() === "pruning") {
  703. // Hide second image
  704. $("#c2image").closest(".col-md-6").hide();
  705. // Remove required validation
  706. $("#c2image").prop("required", false).val("");
  707. $("#address").closest(".col-md-6").hide();
  708. $("#address").prop("required", false).val("");
  709. } else {
  710. // Show second image
  711. $("#c2image").closest(".col-md-6").show();
  712. // Existing workflow
  713. $("#c2image").prop("required", true);
  714. $("#address").closest(".col-md-6").show();
  715. $("#address").prop("required", true);
  716. }*/
  717. if (!id) {
  718. return;
  719. }
  720. $("#naturecontainer").html(`
  721. <div class="row" id="treeRow">
  722. <div class="col-md-4 mb-3">
  723. <label class="form-label">
  724. No. of Trees - ${name}
  725. <span class="text-danger">*</span>
  726. </label>
  727. <input type="number"
  728. class="form-control"
  729. id="trees_${id}"
  730. value="1"
  731. disabled>
  732. </div>
  733. </div>
  734. `);
  735. });
  736. // Handle Complaint Selection (Only One Selection Allowed)
  737. /*$(document).on("change", ".nature-check", function () {
  738. // If checked, uncheck all others
  739. if ($(this).is(":checked")) {
  740. $(".nature-check").not(this).prop("checked", false);
  741. }
  742. // Remove previous tree input
  743. $("#treeRow").remove();
  744. let checked = $(".nature-check:checked");
  745. if (checked.length > 0) {
  746. let id = checked.data("id");
  747. let name = checked.data("name");
  748. $("#naturecontainer").html(`
  749. <div class="row" id="treeRow">
  750. <div class="col-md-4 mb-3">
  751. <label class="form-label">
  752. No. of Trees - ${name}
  753. <span class="text-danger">*</span>
  754. </label>
  755. <input type="number"
  756. class="form-control"
  757. id="trees_${id}"
  758. value="1"
  759. disabled>
  760. </div>
  761. </div>
  762. `);
  763. }
  764. updateDropdownLabel();
  765. });*/
  766. // Update dropdown text with selected names
  767. /*function updateDropdownLabel() {
  768. let selected = [];
  769. $(".nature-check:checked").each(function () {
  770. selected.push($(this).data("name"));
  771. });
  772. if (selected.length === 0) {
  773. $("#dropdownToggle").text("Select Options");
  774. } else {
  775. $("#dropdownToggle").text(selected.join(", "));
  776. }
  777. }*/ /* function updateDropdownLabel() {
  778. let checked = $(".nature-check:checked");
  779. if (checked.length === 0) {
  780. $("#dropdownToggle").text("Select Complaint");
  781. } else {
  782. $("#dropdownToggle").text(checked.data("name"));
  783. }
  784. }*/
  785. });
  786. document.getElementById("backBtn").addEventListener("click", function () {
  787. window.location.href = "/greencommittee/home";
  788. });
  789. //Maximum file size (10 MB)
  790. const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB in bytes
  791. // Apply to all file inputs inside the form
  792. $("#publicform input[type='file']").on("change", function () {
  793. const fileInput = this;
  794. console.log(" cehcking");
  795. if (fileInput.files.length > 0) {
  796. let file = fileInput.files[0];
  797. if (file.size > MAX_FILE_SIZE) {
  798. Swal.fire({
  799. icon: "error",
  800. title: "File too large!",
  801. text: "Maximum allowed file size is 10 MB.",
  802. });
  803. // Clear file input
  804. $(fileInput).val('');
  805. }
  806. }
  807. });
  808. function toggleMenu() {
  809. var dropdown = document.getElementById("menuDropdown");
  810. if (dropdown.style.display === "flex") {
  811. dropdown.style.display = "none";
  812. } else {
  813. dropdown.style.display = "flex";
  814. }
  815. }
  816. function validatePhoneNumber(input) {
  817. input.value = input.value.replace(/[^0-9]/g, '').slice(0, 10);
  818. }
  819. //Script For Map
  820. function myMap() {
  821. const defaultCenter = { lat: 13.0827, lng: 80.2707 };
  822. const map = new google.maps.Map(document.getElementById("googleMap"), {
  823. center: defaultCenter,
  824. zoom: 14
  825. });
  826. let marker = null;
  827. let streetsList = []; // Define globally inside myMap
  828. const infowindow = new google.maps.InfoWindow();
  829. // Initialize the SearchBox
  830. /* const input = document.getElementById('pac-input');
  831. const searchBox = new google.maps.places.SearchBox(input);
  832. //map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
  833. map.addListener('bounds_changed', function () {
  834. searchBox.setBounds(map.getBounds());
  835. });
  836. searchBox.addListener('places_changed', function () {
  837. const places = searchBox.getPlaces();
  838. if (places.length === 0) return;
  839. if (marker) marker.setMap(null);
  840. const place = places[0];
  841. if (!place.geometry) return;
  842. marker = new google.maps.Marker({
  843. map: map,
  844. position: place.geometry.location
  845. });
  846. const lat = place.geometry.location.lat().toFixed(6);
  847. const lng = place.geometry.location.lng().toFixed(6);
  848. document.getElementById("latitude").value = lat;
  849. document.getElementById("longitude").value = lng;
  850. map.setCenter(place.geometry.location);
  851. map.setZoom(15);
  852. infowindow.setContent(`Latitude: ${lat}<br>Longitude: ${lng}`);
  853. infowindow.open(map, marker);
  854. fetchStreets(lat, lng);
  855. }); */
  856. const input = document.getElementById("pac-input");
  857. const suggestions = document.getElementById("suggestions");
  858. const autocompleteService = new google.maps.places.AutocompleteService();
  859. const placesService = new google.maps.places.PlacesService(map);
  860. let debounceTimer = null;
  861. input.addEventListener("input", function () {
  862. clearTimeout(debounceTimer);
  863. const query = this.value.trim();
  864. // Hide suggestions
  865. if (query.length < 5) {
  866. suggestions.style.display = "none";
  867. suggestions.innerHTML = "";
  868. return;
  869. }
  870. debounceTimer = setTimeout(function () {
  871. autocompleteService.getPlacePredictions({
  872. input: query,
  873. bounds: map.getBounds()
  874. }, showPredictions);
  875. }, 500);
  876. });
  877. function showPredictions(predictions, status) {
  878. suggestions.innerHTML = "";
  879. if (
  880. status !== google.maps.places.PlacesServiceStatus.OK ||
  881. !predictions ||
  882. predictions.length === 0
  883. ) {
  884. suggestions.style.display = "none";
  885. return;
  886. }
  887. const ul = document.createElement("ul");
  888. predictions.forEach(function (prediction) {
  889. const li = document.createElement("li");
  890. li.innerHTML = prediction.description;
  891. li.onclick = function () {
  892. input.value = prediction.description;
  893. suggestions.style.display = "none";
  894. loadPlace(prediction.place_id);
  895. };
  896. ul.appendChild(li);
  897. });
  898. suggestions.appendChild(ul);
  899. suggestions.style.display = "block";
  900. }
  901. function loadPlace(placeId) {
  902. placesService.getDetails({
  903. placeId: placeId,
  904. fields: [
  905. "geometry",
  906. "formatted_address",
  907. "name"
  908. ]
  909. }, function (place, status) {
  910. if (status !== google.maps.places.PlacesServiceStatus.OK)
  911. return;
  912. if (marker)
  913. marker.setMap(null);
  914. marker = new google.maps.Marker({
  915. map: map,
  916. position: place.geometry.location
  917. });
  918. const lat = place.geometry.location.lat().toFixed(6);
  919. const lng = place.geometry.location.lng().toFixed(6);
  920. document.getElementById("latitude_field").value = lat;
  921. document.getElementById("longitude_field").value = lng;
  922. map.setCenter(place.geometry.location);
  923. map.setZoom(15);
  924. infowindow.setContent(
  925. "Latitude : " + lat +
  926. "<br>Longitude : " + lng
  927. );
  928. infowindow.open(map, marker);
  929. fetchStreets(lat, lng);
  930. });
  931. }
  932. document.addEventListener("click", function (e) {
  933. if (
  934. !suggestions.contains(e.target) &&
  935. e.target !== input
  936. ) {
  937. suggestions.style.display = "none";
  938. }
  939. });
  940. map.addListener("click", function (event) {
  941. const clickedLatLng = event.latLng;
  942. if (marker) marker.setMap(null);
  943. marker = new google.maps.Marker({
  944. position: clickedLatLng,
  945. map: map
  946. });
  947. const lat = clickedLatLng.lat().toFixed(6);
  948. const lng = clickedLatLng.lng().toFixed(6);
  949. document.getElementById("latitude").value = lat;
  950. document.getElementById("longitude").value = lng;
  951. infowindow.setContent(`Latitude: ${lat}<br>Longitude: ${lng}`);
  952. infowindow.open(map, marker);
  953. fetchStreets(lat, lng);
  954. });
  955. function fetchStreets(lat, lng) {
  956. const encodedGeometry = encodeURIComponent(JSON.stringify({ y: lat, x: lng }));
  957. //const url = `https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/EDPMobile2025/
  958. //FeatureServer/2/query?where=&objectIds=&time=&geometry={encodedGeometry}&geometryType=esriGeometryPoint&inSR=4326&defaultSR=4326&spatialRel=esriSpatialRelIntersects&distance=1&units=esriSRUnit_Meter&outFields=zone,ward&returnGeometry=false&f=geojson`;
  959. const url = `https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/EDPMobile2025/FeatureServer/0/query?` +
  960. `where=&objectIds=&time=&geometry=${encodedGeometry}` +
  961. `&geometryType=esriGeometryPoint&inSR=4326&defaultSR=4326&spatialRel=esriSpatialRelIntersects&distance=25` +
  962. `&units=esriSRUnit_Meter&relationParam=&outFields=region%2Cnew_zone%2C+new_ward%2Croad_id%2C+road_name%2Cgis_id%2Ctype` +
  963. `&returnGeometry=false&maxAllowableOffset=&geometryPrecision=&outSR=&havingClause=&gdbVersion=&historicMoment=` +
  964. `&returnDistinctValues=false&returnIdsOnly=false&returnCountOnly=false&returnExtentOnly=false&orderByFields=` +
  965. `&groupByFieldsForStatistics=&outStatistics=&returnZ=false&returnM=false&multipatchOption=xyFootprint&resultOffset=` +
  966. `&resultRecordCount=&returnTrueCurves=false&returnExceededLimitFeatures=false&quantizationParameters=&returnCentroid=false` +
  967. `&timeReferenceUnknownClient=false&maxRecordCountFactor=&sqlFormat=none&resultType=&featureEncoding=esriDefault` +
  968. `&datumTransformation=&f=geojson`;
  969. //console.log(url);
  970. fetch(url)
  971. .then(response => {
  972. if (!response.ok) {
  973. throw new Error(`HTTP error! Status: ${response.status}`);
  974. }
  975. return response.json();
  976. })
  977. .then(data => {
  978. console.log("GIS API Response:", data);
  979. const features = data.features;
  980. if (features.length > 0) {
  981. const props = features[0].properties;
  982. const zone = props.new_zone;
  983. const ward = props.new_ward;
  984. console.log("Zone:", zone, "Ward:", ward);
  985. // 👉 You can update form fields or DOM elements here
  986. document.getElementById("zone").value = zone;
  987. document.getElementById("ward").value = ward;
  988. } else {
  989. console.warn("No zone/ward found for this location.");
  990. document.getElementById("zone").value = '';
  991. document.getElementById("ward").value = '';
  992. }
  993. })
  994. .catch(error => {
  995. console.error("Error fetching zone/ward:", error);
  996. });
  997. const streetSelect = document.getElementById("streetName");
  998. streetSelect.innerHTML = "";
  999. const defaultOption = document.createElement("option");
  1000. defaultOption.value = "";
  1001. defaultOption.text = "-- Select Street --";
  1002. streetSelect.appendChild(defaultOption);
  1003. document.getElementById("streetId").value = "";
  1004. // Timeout mechanism: 1 seconds
  1005. const timeout = new Promise((_, reject) =>
  1006. setTimeout(() => reject(new Error("Request timed out")), 1000)
  1007. );
  1008. // Actual fetch
  1009. const fetchRequest = fetch(url).then(res => res.json());
  1010. Promise.race([fetchRequest, timeout])
  1011. .then(data => {
  1012. const features = data.features;
  1013. if (!features || features.length === 0) {
  1014. Swal.fire({
  1015. icon: 'warning',
  1016. title: 'No Street Found',
  1017. text: 'Please select the nearby street.',
  1018. });
  1019. return;
  1020. }
  1021. streetsList = features.map(f => f.properties); //Save for use in dropdown
  1022. streetsList.forEach((props, index) => {
  1023. const option = document.createElement("option");
  1024. option.value = index;
  1025. option.text = props.road_name;
  1026. streetSelect.appendChild(option);
  1027. });
  1028. })
  1029. .catch(err => {
  1030. console.error("Error fetching street:", err);
  1031. Swal.fire("Failed to load street data", '', 'error');
  1032. });
  1033. }
  1034. document.getElementById("streetName").addEventListener("change", function () {
  1035. const selectedIndex = this.value;
  1036. console.log("heck")
  1037. console.log(selectedIndex);
  1038. if (selectedIndex !== "") {
  1039. const selectedStreet = streetsList[selectedIndex];
  1040. console.log(selectedStreet);
  1041. document.getElementById("streetId").value = selectedStreet.road_id;
  1042. console.log("Selected street:", selectedStreet);
  1043. } else {
  1044. document.getElementById("streetId").value = "";
  1045. }
  1046. });
  1047. }
  1048. $('#publicform').submit(function (e) {
  1049. e.preventDefault();
  1050. $('#pageLoader').show();
  1051. let formData = new FormData(this);
  1052. $('#submitBtn').prop('disabled', true).text('Submitting...');
  1053. const mobnumber = $('#mobile_no').val().trim();
  1054. if (mobnumber) {
  1055. // Rule 1: Must be exactly 10 digits & must not start with 0
  1056. if (!/^[1-9][0-9]{9}$/.test(mobnumber)) {
  1057. $('#pageLoader').hide();
  1058. $('#submitBtn').prop('disabled', false).text('Submit');
  1059. Swal.fire({
  1060. icon: 'warning',
  1061. title: 'Invalid Mobile Number',
  1062. text: 'Mobile number must be 10 digits and cannot start with 0.'
  1063. });
  1064. return;
  1065. }
  1066. // Rule 2: Reject sequential numbers like 1234567890
  1067. if (mobnumber === "1234567890") {
  1068. $('#pageLoader').hide();
  1069. $('#submitBtn').prop('disabled', false).text('Submit');
  1070. Swal.fire({
  1071. icon: 'warning',
  1072. title: 'Invalid Mobile Number',
  1073. text: 'Sequential numbers like 1234567890 are not allowed.'
  1074. });
  1075. return;
  1076. }
  1077. // Rule 3: Reject all digits same (1111111111, 2222222222, etc.)
  1078. if (/^(\d)\1{9}$/.test(mobnumber)) {
  1079. $('#pageLoader').hide();
  1080. $('#submitBtn').prop('disabled', false).text('Submit');
  1081. Swal.fire({
  1082. icon: 'warning',
  1083. title: 'Invalid Mobile Number',
  1084. text: 'All digits cannot be the same.'
  1085. });
  1086. return;
  1087. }
  1088. }
  1089. const latitude = $('#latitude').val().trim();
  1090. const longitute = $('#longitude').val().trim();
  1091. if (!latitude) {
  1092. $('#pageLoader').hide();
  1093. $('#submitBtn').prop('disabled', false).text('Submit');
  1094. Swal.fire({
  1095. icon: 'warning',
  1096. title: 'Missing latitude',
  1097. text: 'Please Mark or search in street Map.'
  1098. });
  1099. return;
  1100. }
  1101. if (!longitude) {
  1102. $('#pageLoader').hide();
  1103. $('#submitBtn').prop('disabled', false).text('Submit');
  1104. Swal.fire({
  1105. icon: 'warning',
  1106. title: 'Missing longitude',
  1107. text: 'Please Mark or search in street Map.'
  1108. });
  1109. return;
  1110. }
  1111. const zone = $('#zone').val().trim();
  1112. const ward = $('#ward').val().trim();
  1113. if (!zone) {
  1114. $('#pageLoader').hide();
  1115. $('#submitBtn').prop('disabled', false).text('Submit');
  1116. Swal.fire({
  1117. icon: 'warning',
  1118. title: 'Missing Zone',
  1119. text: 'Please Mark or search in street Map.'
  1120. });
  1121. return;
  1122. }
  1123. if (!ward) {
  1124. $('#pageLoader').hide();
  1125. $('#submitBtn').prop('disabled', false).text('Submit');
  1126. Swal.fire({
  1127. icon: 'warning',
  1128. title: 'Missing Ward',
  1129. text: 'Please Mark or search in street Map..'
  1130. });
  1131. return;
  1132. }
  1133. const name = $('#pname').val();
  1134. const streetName = $('#streetName option:selected').text();
  1135. const street_id = $('#streetId').val();
  1136. // console.log("cfefefef");
  1137. console.log(streetName);
  1138. console.log("Streetid");
  1139. console.log(street_id);
  1140. // const streetName = $('#streetName').val();
  1141. const c1image = $('#c1image')[0];
  1142. const c2image = $('#c2image')[0];
  1143. let compDetailsList = [];
  1144. let invalidCount = false;
  1145. let id = $("#complaintDropdown").val();
  1146. if (id) {
  1147. let count = $("#trees_" + id).val();
  1148. if (!count || Number(count) <= 0) {
  1149. invalidCount = true;
  1150. }
  1151. compDetailsList.push({
  1152. id: id,
  1153. count: 1
  1154. });
  1155. }
  1156. /*$(".nature-check:checked").each(function () {
  1157. // let id = $(this).data("id");
  1158. let count = $("#trees_" + id).val();
  1159. // Validate invalid count (empty OR zero-like OR negative)
  1160. if (!count || Number(count) <= 0) {
  1161. invalidCount = true;
  1162. }
  1163. //for default one tree by ak
  1164. let id = $("#complaintDropdown").val();
  1165. if (id) {
  1166. compDetailsList.push({
  1167. id: id,
  1168. count: 1
  1169. });
  1170. }
  1171. });*/
  1172. if (compDetailsList.length === 0) {
  1173. $('#pageLoader').hide();
  1174. $('#submitBtn').prop('disabled', false).text('Submit');
  1175. Swal.fire({
  1176. icon: 'warning',
  1177. title: 'Missing',
  1178. text: 'Details of Complaint.'
  1179. });
  1180. return;
  1181. }
  1182. // If any count = 0
  1183. if (invalidCount) {
  1184. $('#pageLoader').hide();
  1185. $('#submitBtn').prop('disabled', false).text('Submit');
  1186. Swal.fire({
  1187. icon: 'error',
  1188. title: 'Invalid Count',
  1189. text: 'Please enter a valid count for all selected complaint Details.'
  1190. });
  1191. return;
  1192. }
  1193. formData.append("ph_no", mobnumber);
  1194. formData.append("p_name", name);
  1195. formData.append("source", "1");
  1196. //formData.append("address", streetName)
  1197. formData.set("streetName", streetName);
  1198. let address = $("#address").val().trim();
  1199. // formData.append("address", address)
  1200. formData.append("c1image", c1image);
  1201. formData.append("c2image", c2image);
  1202. formData.append("comp_details", JSON.stringify(compDetailsList));
  1203. let complaintName = $("#complaintDropdown option:selected").data("name");
  1204. let apiUrl = "/greencommittee/api/savepublicform";
  1205. if (complaintName &&
  1206. complaintName.trim().toLowerCase() === "pruning") {
  1207. if (name.length > 31) {
  1208. $('#pageLoader').hide();
  1209. $('#submitBtn').prop('disabled', false).text('Submit');
  1210. Swal.fire({
  1211. icon: "warning",
  1212. title: "Invalid Petitioner Name",
  1213. text: "Petitioner name cannot exceed 31 characters."
  1214. });
  1215. return; // Stop form submission
  1216. }
  1217. const file = $("#c1image")[0].files[0];
  1218. if (!file) {
  1219. $('#pageLoader').hide();
  1220. $('#submitBtn').prop('disabled', false).text('Submit');
  1221. Swal.fire({
  1222. icon: "warning",
  1223. title: "Image Required",
  1224. text: "Please upload Image 1."
  1225. });
  1226. return;
  1227. }
  1228. // Allow only JPG, JPEG, PNG
  1229. const allowedTypes = ["image/jpeg", "image/jpg", "image/png"];
  1230. if (!allowedTypes.includes(file.type)) {
  1231. $('#pageLoader').hide();
  1232. $('#submitBtn').prop('disabled', false).text('Submit');
  1233. Swal.fire({
  1234. icon: "warning",
  1235. title: "Invalid File",
  1236. text: "Only JPG, JPEG and PNG images are allowed."
  1237. });
  1238. $("#c1image").val("");
  1239. return;
  1240. }
  1241. // Maximum size: 1 MB
  1242. if (file.size > (1 * 1024 * 1024)) {
  1243. $('#pageLoader').hide();
  1244. $('#submitBtn').prop('disabled', false).text('Submit');
  1245. Swal.fire({
  1246. icon: "warning",
  1247. title: "File Too Large",
  1248. text: "Image size should not exceed 1 MB."
  1249. });
  1250. $("#c1image").val("");
  1251. return;
  1252. }
  1253. apiUrl = "/greencommittee/api/savepruningform";
  1254. formData.append("StreetId", street_id);
  1255. // Only one image for pruning
  1256. formData.delete("c2image");
  1257. }
  1258. console.log(formData);
  1259. $.ajax({
  1260. url: apiUrl,
  1261. method: "POST",
  1262. data: formData,
  1263. processData: false,
  1264. contentType: false,
  1265. success: function (response) {
  1266. $('#pageLoader').hide();
  1267. /*if (response.status) {
  1268. Swal.fire({
  1269. icon: 'success',
  1270. allowOutsideClick: false,
  1271. allowEscapeKey: false,
  1272. title: 'Details are Saved Successfully',
  1273. html: 'Reference ID: <b>' + response.ref_id + '</b>'
  1274. }).then(() => {
  1275. window.location.href = "/greencommittee/home";
  1276. });
  1277. }*/
  1278. if (response.status) {
  1279. if (complaintName &&
  1280. complaintName.trim().toLowerCase() === "pruning") {
  1281. Swal.fire({
  1282. icon: 'success',
  1283. allowOutsideClick: false,
  1284. allowEscapeKey: false,
  1285. title: 'Complaint Registered Successfully',
  1286. html: 'Complaint Number: <b>' + response.complaintNumber + '</b>'
  1287. }).then(() => {
  1288. window.location.href = "/greencommittee/home";
  1289. });
  1290. } else {
  1291. Swal.fire({
  1292. icon: 'success',
  1293. allowOutsideClick: false,
  1294. allowEscapeKey: false,
  1295. title: 'Details are Saved Successfully',
  1296. html: 'Reference ID: <b>' + response.ref_id + '</b>'
  1297. }).then(() => {
  1298. window.location.href = "/greencommittee/home";
  1299. });
  1300. }
  1301. }
  1302. else {
  1303. $('#pageLoader').hide();
  1304. Swal.fire({
  1305. icon: 'error',
  1306. title: 'Save Failed',
  1307. text: response.description || 'Something went wrong!'
  1308. });
  1309. }
  1310. $('#submitBtn').prop('disabled', false).text('Submit');
  1311. },
  1312. error: function () {
  1313. $('#pageLoader').hide();
  1314. Swal.fire({
  1315. icon: 'error',
  1316. title: 'Submission Error',
  1317. text: 'Something went wrong while submitting the form.'
  1318. });
  1319. $('#submitBtn').prop('disabled', false).text('Submit');
  1320. }
  1321. });
  1322. });
  1323. </script>
  1324. <script>
  1325. //make sure these variables are in a scope accessible to both handlers
  1326. var resendTimeout = null;
  1327. var timeleft = 0;
  1328. // helper to start the resend countdown (creates the countdown span and updates it every second)
  1329. function startResendCountdown(seconds) {
  1330. // clear any previous interval
  1331. if (resendTimeout) {
  1332. clearInterval(resendTimeout);
  1333. resendTimeout = null;
  1334. }
  1335. timeleft = seconds;
  1336. // Insert the "Please wait.. <span id='countdown'>60</span>s" into the existing container.
  1337. // We keep the same container id (#resend-link) that you already have in HTML,
  1338. // but we avoid creating duplicate ids later.
  1339. $("#resend-link").html('Please wait..<span id="countdown">' + timeleft + '</span>s');
  1340. // Now get the countdown element AFTER it's been added to DOM
  1341. var $countdown = $("#countdown");
  1342. // start interval
  1343. resendTimeout = setInterval(function () {
  1344. timeleft--;
  1345. // only update if the element exists
  1346. if ($countdown.length) $countdown.text(timeleft);
  1347. if (timeleft <= 0) {
  1348. clearInterval(resendTimeout);
  1349. resendTimeout = null;
  1350. // replace the content with an anchor that calls the global sendOTP() function
  1351. // note: we deliberately DO NOT reuse id "resend-link" for the anchor (to avoid duplicate ids)
  1352. // but we put it inside the same container so existing CSS/placement remains unchanged
  1353. $("#resend-link").html('<a href="#" class="text-info resend-anchor" onclick="return sendOTP();">Resend OTP</a>');
  1354. }
  1355. }, 1000);
  1356. }
  1357. // global function used by the generated "Resend OTP" anchor
  1358. window.sendOTP = function () {
  1359. // read the mobile number currently shown in the modal or the input
  1360. // prefer reading from mobilenotxt (displayed) so flow remains same
  1361. var mobileNumber = $("#mobilenotxt").text() || $("#mobile_no").val();
  1362. if (!mobileNumber || mobileNumber.length !== 10) {
  1363. alert("Please enter a valid 10-digit mobile number.");
  1364. return false; // prevent anchor default
  1365. }
  1366. // Optional: disable the anchor while sending (prevents double-click)
  1367. $(".resend-anchor").prop("disabled", true);
  1368. $.ajax({
  1369. type: "GET",
  1370. url: '/greencommittee/api/sendOTP',
  1371. data: { 'mobileNo': mobileNumber },
  1372. dataType: 'json',
  1373. success: function (response) {
  1374. /* if (response === "Error: This number is not registered.") {
  1375. alert("This number is not registered.");
  1376. // restore the container content (or you could keep it as a simple text)
  1377. $("#resend-link").text("Didn't receive OTP?");
  1378. } */ if (response !== "Error") {
  1379. // Re-show the modal (if it was hidden) and restart countdown
  1380. $(".otp-input").val('');
  1381. $("#otperror").html("");
  1382. $('#otpForm').modal({
  1383. backdrop: 'static',
  1384. keyboard: false
  1385. });
  1386. $('#otpForm').modal('show');
  1387. // restart countdown for 60s
  1388. startResendCountdown(60);
  1389. } else {
  1390. alert("OTP not sent. Please try again.");
  1391. }
  1392. },
  1393. error: function () {
  1394. alert("Issue in OTP");
  1395. },
  1396. complete: function () {
  1397. // re-enable the anchor if it exists
  1398. $(".resend-anchor").prop("disabled", false);
  1399. }
  1400. });
  1401. return false; // prevent anchor default navigation
  1402. };
  1403. //For OTP input box
  1404. $('.otp-input').on('keyup', function (e) {
  1405. var $this = $(this);
  1406. if ($this.val().length === 1) {
  1407. $this.next('.otp-input').focus();
  1408. }
  1409. if ($this.val().length === 0) {
  1410. $this.prev('.otp-input').focus();
  1411. }
  1412. });
  1413. //verify otp
  1414. function verifyOtp() {
  1415. var otpInputs = $('.otp-input');
  1416. var otpValue = '';
  1417. otpInputs.each(function () {
  1418. otpValue += $(this).val();
  1419. });
  1420. //console.log("otpValue="+otpValue);
  1421. $.ajax({
  1422. type: "GET",
  1423. url: '/greencommittee/api/verifyOTP',
  1424. data: { 'otp': otpValue },
  1425. dataType: 'text',
  1426. success: function (bodyMessage) {
  1427. if (bodyMessage.trim() === "Success") {
  1428. $('#otpForm').modal('hide');
  1429. //console.log("OTP is Verified!!!");
  1430. mobile_valid = true;
  1431. if (mobile_valid) {
  1432. $("#submitBtn").prop("disabled", false);
  1433. }
  1434. Swal.fire({
  1435. icon: "success",
  1436. title: "Success",
  1437. text: "OTP Verified Successfully",
  1438. });
  1439. //location.reload();
  1440. // Proceeds to save form or next action
  1441. $('#otpbeforeverified').hide();
  1442. $('#otpafterverified').show();
  1443. } else {
  1444. $("#otperror").html("OTP is Incorrect!!!");
  1445. }
  1446. },
  1447. error: function () {
  1448. console.log("Error");
  1449. }
  1450. });
  1451. return false;
  1452. }
  1453. $(document).ready(function () {
  1454. $("#address").closest(".col-md-6").hide();
  1455. $("#address").prop("required", false);
  1456. $('#sendOtpButton').click(function () {
  1457. // Get the entered mobile number
  1458. const mobileNumber = $('#mobile_no').val();
  1459. // Basic check to ensure mobile number is entered
  1460. if (mobileNumber.length === 10) {
  1461. // Display the mobile number in the OTP modal
  1462. $("#mobilenotxt").html(mobileNumber);
  1463. $.ajax({
  1464. type: "GET",
  1465. url: '/greencommittee/api/sendOTP',
  1466. data: { 'mobileNo': mobileNumber }, // Pass mobile number and purpose
  1467. dataType: 'json',
  1468. success: function (response) {
  1469. /* if (response === "Error: This number is not registered.") {
  1470. alert("This number is not registered.");
  1471. } */ if (response !== "Error") {
  1472. // Open OTP Modal
  1473. $(".otp-input").val('');
  1474. $("#otperror").html("");
  1475. $('#otpForm').modal({
  1476. backdrop: 'static',
  1477. keyboard: false
  1478. });
  1479. $('#otpForm').modal('show');
  1480. // Start countdown for resend OTP (60 seconds)
  1481. startResendCountdown(60);
  1482. } else {
  1483. alert("OTP not sent. Please try again.");
  1484. }
  1485. },
  1486. error: function () {
  1487. alert("Issue in OTP");
  1488. }
  1489. });
  1490. } else {
  1491. //alert("Please enter a valid 10-digit mobile number.");
  1492. Swal.fire({
  1493. icon: "warning",
  1494. title: "Validation",
  1495. text: "Please enter a valid 10-digit mobile number.",
  1496. });
  1497. }
  1498. });
  1499. });
  1500. </script>
  1501. </body>
  1502. </html>