diff --git a/backend/main.go b/backend/main.go index c1c0549..1a2cde6 100644 --- a/backend/main.go +++ b/backend/main.go @@ -12,16 +12,16 @@ import ( // "errors" // "os" - // "github.com/gin-contrib/cors" + "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" _ "github.com/go-sql-driver/mysql" ) // DEV -// var connection string = "root:superuser@tcp(localhost:3306)/iips" +var connection string = "root:superuser@tcp(localhost:3306)/iips" // SERVER -var connection string = "iips:iipsuser@tcp(192.168.7.100:3306)/iips" +// var connection string = "iips:iipsuser@tcp(192.168.7.100:3306)/iips" func main() { connect() @@ -37,24 +37,23 @@ func connect() { defer db.Close() router := gin.Default() - // router.Use(cors.Default()) + router.Use(cors.Default()) //DEV - // router.Use(cors.New(cors.Config{ - // AllowOrigins: []string{"http://localhost:5173"}, - // // AllowAllOrigins: true, - // AllowMethods: []string{"GET", "POST"}, - // AllowHeaders: []string{"Origin", "OCBO-ShieldConnection"}, - // ExposeHeaders: []string{"Content-Length"}, - // AllowCredentials: true, - // })) + router.Use(cors.New(cors.Config{ + AllowOrigins: []string{"http://localhost:5173"}, + AllowMethods: []string{"GET", "POST"}, + AllowHeaders: []string{"Origin", "OCBO-ShieldConnection"}, + ExposeHeaders: []string{"Content-Length"}, + AllowCredentials: true, + })) //SERVER // router.Use(cors.New(cors.Config{ // // AllowOrigins: []string{"http://192.168.7.160:8080/esign"}, - // AllowAllOrigins: true, - // AllowMethods: []string{"GET", "POST"}, - // AllowHeaders: []string{"Origin", "OCBO-ShieldConnection"}, + // AllowAllOrigins: true, + // AllowMethods: []string{"GET", "POST", "OPTIONS"}, + // AllowHeaders: []string{"Origin"}, // ExposeHeaders: []string{"Content-Length"}, // AllowCredentials: true, // })) @@ -101,7 +100,7 @@ func connect() { array2 := []string{} results, err := db.Query(`SELECT IFNULL(e.electricalno, '') AS result, IF(c.firstName IS NULL OR c.firstName = '', c.lastName, CONCAT(c.firstName, ' ', IF(c.middleInitial IS NULL OR c.middleInitial = '', '', CONCAT(c.middleInitial, '. ')), c.lastName) ) AS result2 - FROM iips.electrical e JOIN iips.customer c ON e.customerid = c.customerid JOIN iips.ref_elec_occupancy ec ON e.ref_elec_occupancyid = ec.ref_elec_occupancyid JOIN iips.electricaldocflowtxn ed ON e.electricalid = ed.electricalid JOIN (SELECT electricalid, MAX(electricaldocflowtxnid) AS latest_electricaldocflowtxnid FROM electricaldocflowtxn GROUP BY electricalid) latest_doc ON ed.electricalid = latest_doc.electricalid AND ed.electricaldocflowtxnid = latest_doc.latest_electricaldocflowtxnid WHERE remarks = ? AND is_approve = 0 ORDER BY e.electricalno ASC`, "FOR ELECTRICAL ORDER OF PAYMENT APPROVAL") + FROM iips.electrical e JOIN iips.customer c ON e.customerid = c.customerid JOIN iips.ref_elec_occupancy ec ON e.ref_elec_occupancyid = ec.ref_elec_occupancyid JOIN iips.electricaldocflowtxn ed ON e.electricalid = ed.electricalid JOIN (SELECT electricalid, MAX(electricaldocflowtxnid) AS latest_electricaldocflowtxnid FROM electricaldocflowtxn GROUP BY electricalid) latest_doc ON ed.electricalid = latest_doc.electricalid AND ed.electricaldocflowtxnid = latest_doc.latest_electricaldocflowtxnid WHERE remarks = ? AND is_approve = 0 ORDER BY ed.txndate DESC`, "FOR ELECTRICAL ORDER OF PAYMENT APPROVAL") if err != nil { c.AbortWithError(http.StatusBadRequest, err) c.String(http.StatusBadRequest, err.Error()) @@ -726,6 +725,17 @@ func connect() { "result": result, }) + case "get-esignid": + err := db.QueryRow("SELECT IFNULL(esignid, 0) AS result FROM esign WHERE employeeid = ?", data).Scan(&result) + if err != nil { + c.AbortWithError(http.StatusBadRequest, err) + c.String(http.StatusBadRequest, err.Error()) + return + } + c.JSON(http.StatusOK, gin.H{ + "result": result, + }) + } }) @@ -753,6 +763,17 @@ func connect() { c.JSON(http.StatusOK, gin.H{ "result": result, }) + + case "get-signeddate": + err := db.QueryRow("SELECT IFNULL(date_signed, '') AS result FROM esign_transactions WHERE esignid = ? AND referenceNo = ?", data, data2).Scan(&result) + if err != nil { + c.AbortWithError(http.StatusBadRequest, err) + c.String(http.StatusBadRequest, err.Error()) + return + } + c.JSON(http.StatusOK, gin.H{ + "result": result, + }) } }) @@ -927,5 +948,47 @@ func connect() { } }) + router.POST("/api/post-esigntransaction", func(c *gin.Context) { + type UpdateOpData struct { + Data int `json:"data"` + Data2 string `json:"data2"` + Data3 string `json:"data3"` + } + var updateOpData UpdateOpData + if err := c.ShouldBindJSON(&updateOpData); err != nil { + c.String(http.StatusBadRequest, "Invalid request body") + return + } + + c.Writer.Header().Set("X-XSS-Protection", "1; mode=block") + c.Writer.Header().Set("X-Content-Type-Options", "nosniff") + c.Writer.Header().Set("X-DNS-Prefetch-Control", "off") + c.Writer.Header().Set("X-Frame-Options", "DENY") + c.Writer.Header().Set("X-Download-Options", "noopen") + c.Writer.Header().Set("Referrer-Policy", "no-referrer") + + dbpost, err := db.Prepare("INSERT INTO esign_transactions (esign_transactionsid, esignid, referenceNo, date_signed) VALUES (NULL, ?, ?, ?)") + if err != nil { + panic(err.Error()) + } + defer dbpost.Close() + + exec, err := dbpost.Exec(updateOpData.Data, updateOpData.Data2, updateOpData.Data3) + if err != nil { + panic(err.Error()) + } + + affect, err := exec.RowsAffected() + if err != nil { + panic(err.Error()) + } + + if affect > 0 { + c.String(http.StatusOK, "Success on Saving eSign transaction") + } else { + c.String(http.StatusInternalServerError, "Failed on Saving eSign transaction") + } + }) + router.Run(":4320") } diff --git a/public/lungsod.png b/public/lungsod.png new file mode 100644 index 0000000..faa6c50 Binary files /dev/null and b/public/lungsod.png differ diff --git a/public/ocbologo.png b/public/ocbologo.png new file mode 100644 index 0000000..7cd433f Binary files /dev/null and b/public/ocbologo.png differ diff --git a/src/components/Input/Input.tsx b/src/components/Input/Input.tsx index e955bf6..990d391 100644 --- a/src/components/Input/Input.tsx +++ b/src/components/Input/Input.tsx @@ -7,6 +7,7 @@ interface Props { value: string onChange: Setter onKeyDown?: (event: KeyboardEvent) => void + isPassword?: boolean } export default (props: Props) => { @@ -16,7 +17,7 @@ export default (props: Props) => { {props.label} - + ) diff --git a/src/pages/AssessorPage/Assessor.tsx b/src/pages/AssessorPage/Assessor.tsx index c0491a5..bcd053c 100644 --- a/src/pages/AssessorPage/Assessor.tsx +++ b/src/pages/AssessorPage/Assessor.tsx @@ -9,7 +9,7 @@ import { checkConnection, createPdf } from '../../utils/functions' import { FaSolidThumbsUp } from 'solid-icons/fa' import { _employeeName, _employeeId } from '../../stores/employee' import { useNavigate } from '@solidjs/router' -import { _applicationNo, _date, _optn, _name, _location, _type, _assessor, _feeList, _codeList, _amountList, _signature, _assessorid } from '../../stores/pdfinfo' +import { _applicationNo, _date, _optn, _name, _location, _type, _assessor, _feeList, _codeList, _amountList, _signatureAssessor, _signatureApprover, _assessorid, _approvedDate } from '../../stores/pdfinfo' const API = import.meta.env.VITE_BACKEND const PESO = import.meta.env.VITE_PESO @@ -209,6 +209,7 @@ export default () => { updateOrderofpayment = await updateOp() if (updateOrderofpayment) { + postTransaction(application) setPrintedApplication(application) setPrinted(true) createPdf() @@ -248,13 +249,50 @@ export default () => { try { const response = await ofetch(API + 'get-signatureimage/' + id, { parseResponse: JSON.parse }) const image = response.result - _signature.set(image) + _signatureAssessor.set(image) + + const response2 = await ofetch(API + 'get-signatureimage/' + 276, { parseResponse: JSON.parse }) + const image2 = response2.result + _signatureApprover.set(image2) return true } catch { return false } } + const geteSignId = async () => { + try { + const response = await ofetch(API + 'get-esignid/' + employeeId(), { parseResponse: JSON.parse }) + const result = response.result + return result + } catch { + return 0 + } + } + + const postTransaction = async (application: string) => { + const id = await geteSignId() + const today = new Date() + const formatedDate = dayjs(today).format('YYYY-MM-DD HH:mm:ss') + + await ofetch(API + 'post-esigntransaction', { + method: 'POST', + body: { data: parseInt(id), data2: application, data3: formatedDate }, + }) + + getApprovedDate(id, application) + } + + const getApprovedDate = async (id: number, application: string) => { + try { + const response = await ofetch(API + `get-signeddate/${id}/${application}`, { parseResponse: JSON.parse }) + const result = response.result + _approvedDate.set(result) + } catch (error) { + _approvedDate.set('') + } + } + const logout = async () => { removeEmployee() navigate('/') diff --git a/src/pages/LoginPage/Login.tsx b/src/pages/LoginPage/Login.tsx index 97ffe6a..3c3db1b 100644 --- a/src/pages/LoginPage/Login.tsx +++ b/src/pages/LoginPage/Login.tsx @@ -122,6 +122,7 @@ export default () => {

Password

{ diff --git a/src/pages/MainPage/Main.tsx b/src/pages/MainPage/Main.tsx index 43554ef..19318e5 100644 --- a/src/pages/MainPage/Main.tsx +++ b/src/pages/MainPage/Main.tsx @@ -107,6 +107,7 @@ export default () => { if (updateOrderofpayment) { setApprovedApplication(application) setApproved(true) + postTransaction() } } @@ -191,6 +192,26 @@ export default () => { return true } + const geteSignId = async () => { + try { + const response = await ofetch(API + 'get-esignid/' + ID, { parseResponse: JSON.parse }) + const result = response.result + return result + } catch { + return 0 + } + } + + const postTransaction = async () => { + const id = await geteSignId() + const today = new Date() + const formatedDate = dayjs(today).format('YYYY-MM-DD HH:mm:ss') + await ofetch(API + 'post-esigntransaction', { + method: 'POST', + body: { data: parseInt(id), data2: approvedApplication(), data3: formatedDate }, + }) + } + const logout = async () => { removeEmployee() navigate('/') diff --git a/src/pages/RegisterPage/Register.tsx b/src/pages/RegisterPage/Register.tsx index 7463158..4d0d6b3 100644 --- a/src/pages/RegisterPage/Register.tsx +++ b/src/pages/RegisterPage/Register.tsx @@ -174,7 +174,7 @@ export default () => {

Password

- +

Upload Signature

setFile(data)} accept=".jpg, .jpeg, .png, .webp, .avif"> Drag and drop or click to upload file @@ -242,7 +242,7 @@ export default () => { {APPROVERNAME}

Password

- +

Upload Signature

diff --git a/src/stores/pdfinfo.ts b/src/stores/pdfinfo.ts index 9c8b074..6d3299e 100644 --- a/src/stores/pdfinfo.ts +++ b/src/stores/pdfinfo.ts @@ -14,4 +14,7 @@ export const _feeList = atom([]) export const _codeList = atom([]) export const _amountList = atom([]) -export const _signature = atom('') +export const _signatureAssessor = atom('') +export const _signatureApprover = atom('') + +export const _approvedDate = atom('') diff --git a/src/utils/functions/createPdf.ts b/src/utils/functions/createPdf.ts index 0b01fb7..f093eee 100644 --- a/src/utils/functions/createPdf.ts +++ b/src/utils/functions/createPdf.ts @@ -1,7 +1,7 @@ import jsPDF from 'jspdf' // @ts-ignore import jspdfBarcode from 'jspdf-barcode' -import { _optn, _applicationNo, _date, _name, _type, _location, _assessor, _feeList, _codeList, _amountList, _signature, _assessorid } from '../../stores/pdfinfo' +import { _optn, _applicationNo, _date, _name, _type, _location, _assessor, _feeList, _codeList, _amountList, _signatureAssessor, _signatureApprover, _assessorid, _approvedDate } from '../../stores/pdfinfo' import dayjs from 'dayjs' // @ts-ignore import QRCode from 'qrcode' @@ -22,7 +22,7 @@ export default async () => { const CODES = _codeList.get() const AMOUNTS = _amountList.get() const ASSESSORID = _assessorid.get() - const APPROVERID = 176 + const APPROVERID = 276 const doc = new jsPDF({ orientation: 'l', @@ -48,17 +48,17 @@ export default async () => { const pageWidth = doc.internal.pageSize.getWidth() const lungsod = new Image() - lungsod.src = 'src/assets/images/lungsod.png' + lungsod.src = 'lungsod.png' const ocbo = new Image() - ocbo.src = 'src/assets/images/ocbologo.png' + ocbo.src = 'ocbologo.png' jspdfBarcode(doc, APPLICATION, { fontSize: 32, textColor: '#000000', x: pageWidth - 35, y: 40, - textOptions: { align: 'center' }, // optional text options + textOptions: { align: 'center' }, }) const generateQR = async (text: string) => { @@ -229,17 +229,17 @@ export default async () => { const note = doc.splitTextToSize('Note: The 72 Hours Transaction Policy of the City Mayor, shall commence upon submission of the Bureau of Fire Protection clearance/certificate and other requirement stated in the notice to comply to be issued by this office.', 185) doc.text(note, 16, 144) - doc.addImage(_signature.get(), 'PNG', 30, 110, 10, 5.9, 'signature', 'NONE', 0) + doc.addImage(_signatureAssessor.get(), 'PNG', 30, 110, 10, 5.9, 'signatureAssessor', 'NONE', 0) doc.setFont('arial', 'normal') doc.setFontSize(4) doc.text('Digitally signed by :', 30, 118) doc.text(ASSESSOR, 30, 120) doc.text('Date: ' + dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss'), 30, 122) - doc.addImage(_signature.get(), 'PNG', 156, 110, 10, 5.9, 'signature', 'NONE', 0) + doc.addImage(_signatureApprover.get(), 'PNG', 156, 110, 41.4, 5.9, 'signatureApprover', 'NONE', 0) doc.text('Digitally signed by :', 156, 118) doc.text(APPROVER, 156, 120) - doc.text('Date: ' + dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss'), 156, 122) + doc.text('Date: ' + dayjs(_approvedDate.get()).format('YYYY-MM-DD HH:mm:ss'), 156, 122) doc.addImage(assessorQr, 'PNG', 16, 110, 14, 14, 'assessorQr', 'NONE', 0) doc.addImage(approverQr, 'PNG', 142, 110, 14, 14, 'approverQr', 'NONE', 0)