Compare commits

...

13 commits

20 changed files with 404 additions and 359 deletions

1
.env
View file

@ -1,6 +1,7 @@
VITE_BACKEND=http://localhost:4320/api/ VITE_BACKEND=http://localhost:4320/api/
# VITE_BACKEND=https://ocboapps.davaocity.gov.ph/esign-server/api/ # VITE_BACKEND=https://ocboapps.davaocity.gov.ph/esign-server/api/
# VITE_BACKEND=http://192.168.7.163/server/api/ # VITE_BACKEND=http://192.168.7.163/server/api/
VITE_HEAD=ARCH. KHASHAYAR L. TOGHYANI VITE_HEAD=ARCH. KHASHAYAR L. TOGHYANI
VITE_PESO= VITE_PESO=
VITE_HEADID=276 VITE_HEADID=276

View file

@ -71,7 +71,7 @@ func connect() {
router.StaticFile("/", "static/index.html") router.StaticFile("/", "static/index.html")
router.StaticFile("/esign.webp", "static/esign.webp") router.StaticFile("/esign.webp", "static/esign.webp")
router.StaticFile("/favicon.png", "static/favicon.png") router.StaticFile("/favicon.ico", "static/favicon.ico")
// shield := "inquiry" // shield := "inquiry"
@ -613,7 +613,7 @@ func connect() {
}) })
case "check-registered": case "check-registered":
err := db.QueryRow("SELECT IFNULL(esignid, 0) AS result FROM esign WHERE employeeid = ?", data).Scan(&result) err := db.QueryRow("SELECT IFNULL(e.esignid, 0) AS result FROM esign e LEFT JOIN employee emp ON e.employeeid = emp.employeeid WHERE emp.employeename = ?", data).Scan(&result)
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
result = "0" result = "0"

BIN
backend/static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -6,7 +6,7 @@
<meta name="name" content="OCBO e-Sign Server" /> <meta name="name" content="OCBO e-Sign Server" />
<meta name="description" content="Backend application for OCBO e-Sign" /> <meta name="description" content="Backend application for OCBO e-Sign" />
<meta name="developer" content="Patrick Alvin Alcala" /> <meta name="developer" content="Patrick Alvin Alcala" />
<link rel="icon" type="image/png" href="/favicon.png" /> <link rel="icon" type="image/x-icon" href="/favicon.ico" />
<title>OCBO e-Sign Server</title> <title>OCBO e-Sign Server</title>
<style> <style>
body { body {

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View file

@ -8,13 +8,14 @@ interface Props {
curved?: boolean curved?: boolean
padding?: string padding?: string
background?: string background?: string
width?: string
} }
export default (props: Props) => { export default (props: Props) => {
const boxClass = createMemo(() => (props.curved ? 'curvedbox' : 'box')) const boxClass = createMemo(() => (props.curved ? 'curvedbox' : 'box'))
return ( return (
<section class={boxClass()} style={`border: ${props.thickness}px solid ${props.color || 'white'}; padding: ${props.padding || 0}; background-color: ${props.background || 'none'}`}> <section class={boxClass()} style={`border: ${props.thickness}px solid ${props.color || 'white'}; padding: ${props.padding || 0}; background-color: ${props.background || 'none'}; width: ${props.width || 'auto'}`}>
{props.children} {props.children}
</section> </section>
) )

View file

@ -1,7 +1,6 @@
.combobox__control .combobox__control
display: inline-flex display: inline-flex
justify-content: space-between justify-content: space-between
width: 500px
border-radius: 6px border-radius: 6px
font-size: 16px font-size: 16px
line-height: 1 line-height: 1
@ -34,7 +33,7 @@
width: 40rem width: 40rem
&::placeholder &::placeholder
color: #517aa2d2 color: #a3bfd9d2
.combobox__trigger .combobox__trigger
appearance: none appearance: none
@ -71,14 +70,13 @@
user-select: none user-select: none
.combobox__content .combobox__content
background-color: #0d131ae0 background-color: #0d131af4
backdrop-filter: blur(8px) backdrop-filter: blur(8px)
border-radius: 6px border-radius: 6px
border: 1px solid hsl(240 6% 90%) border: 1px solid hsl(240 6% 90%)
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1) box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)
transform-origin: var(--kb-combobox-content-transform-origin) transform-origin: var(--kb-combobox-content-transform-origin)
animation: contentHide 250ms ease-in forwards animation: contentHide 250ms ease-in forwards
color: red
&[data-expanded] &[data-expanded]
animation: contentShow 250ms ease-out animation: contentShow 250ms ease-out
@ -113,7 +111,7 @@
&[data-highlighted] &[data-highlighted]
outline: none outline: none
background-color: hsl(200 98% 39%) background-color: #37506df4
color: white color: white
.combobox__section .combobox__section

View file

@ -8,6 +8,7 @@ interface Props {
placeholder: string placeholder: string
value: string value: string
onChange: (value: string | null) => void onChange: (value: string | null) => void
width?: string
} }
export default (props: Props) => { export default (props: Props) => {
@ -28,7 +29,7 @@ export default (props: Props) => {
</Combobox.Item> </Combobox.Item>
)} )}
> >
<Combobox.Control class="combobox__control" aria-label="Assessors"> <Combobox.Control class="combobox__control" aria-label="Assessors" style={`width: ${props.width || '500px'}`}>
<Combobox.Input class="combobox__input" /> <Combobox.Input class="combobox__input" />
<Combobox.Trigger class="combobox__trigger"> <Combobox.Trigger class="combobox__trigger">
<Combobox.Icon class="combobox__icon"> <Combobox.Icon class="combobox__icon">

View file

@ -17,6 +17,12 @@
background-attachment: fixed background-attachment: fixed
background-size: cover background-size: cover
@media only screen and (max-width: views.$mobile)
background-image: url('/src/assets/images/optimized/background-mobile.avif'), url('/src/assets/images/optimized/background-mobile.webp')
min-width: 100vw
min-height: 100vh
object-fit: fill
.close-text .close-text
padding: 3rem 0 0 0 padding: 3rem 0 0 0
font-size: 0.75rem font-size: 0.75rem

View file

@ -1,7 +1,7 @@
import './Index.sass' import './Index.sass'
import { Button, Page, Padding, Display, Row, Logo, Footer, Copyright, Column, Image, Box } from '../../components' import { Button, Page, Padding, Display, Row, Logo, Footer, Copyright, Column, Image, Box } from '../../components'
import { getApi } from '../../utils/functions'
import { onMount } from 'solid-js' import { onMount } from 'solid-js'
import { ofetch } from 'ofetch'
import ocboAvif from '../../assets/images/optimized/ocbologo.avif' import ocboAvif from '../../assets/images/optimized/ocbologo.avif'
import ocboWebp from '../../assets/images/optimized/ocbologo.webp' import ocboWebp from '../../assets/images/optimized/ocbologo.webp'
import patAvif from '../../assets/images/optimized/pat-alcala.avif' import patAvif from '../../assets/images/optimized/pat-alcala.avif'
@ -9,36 +9,20 @@ import patWebp from '../../assets/images/optimized/pat-alcala.webp'
import pageLogoAvif from '../../assets/images/optimized/esign.avif' import pageLogoAvif from '../../assets/images/optimized/esign.avif'
import pageLogoWebp from '../../assets/images/optimized/esign.webp' import pageLogoWebp from '../../assets/images/optimized/esign.webp'
const API = import.meta.env.VITE_BACKEND
let assessorsNameList: string[] let assessorsNameList: string[]
let registeredNameList: string[] let registeredNameList: string[]
export default () => { export default () => {
const getAssessors = async () => { const getAssessors = async () => {
try { const assessors = await getApi('get-list-assessors')
const assessors = await ofetch(API + 'get-list-assessors', { parseResponse: JSON.parse }) assessorsNameList = [...assessors]
assessorsNameList = [...assessors.result]
} catch (error) {
console.error(error)
}
sessionStorage.setItem('assessors', JSON.stringify([...assessorsNameList])) sessionStorage.setItem('assessors', JSON.stringify([...assessorsNameList]))
} }
const getRegistered = async () => { const getRegistered = async () => {
// let nameList: string[] = [] const registered = await getApi('get-list-registered')
registeredNameList = [...registered]
try {
const registered = await ofetch(API + 'get-list-registered', { parseResponse: JSON.parse })
// for (let i = 0; i < registered.result.length; i++) {
// const name = await ofetch(API + 'get-employeename/' + registered.result[i], { parseResponse: JSON.parse })
// nameList.push(name.result)
// }
registeredNameList = [...registered.result]
} catch (error) {
console.error(error)
}
sessionStorage.setItem('registered', JSON.stringify([...registeredNameList])) sessionStorage.setItem('registered', JSON.stringify([...registeredNameList]))
} }
@ -159,14 +143,9 @@ export default () => {
<Display mobile> <Display mobile>
<Column> <Column>
<Logo size={200} /> <Logo size={120} />
<h1>OCBO e-Sign</h1> <h1>OCBO e-Sign</h1>
<Image avif={pageLogoAvif} webp={pageLogoWebp} size={200}></Image> <span>Please use OCBO e-Sign Mobile Version</span>
<section class="mobile-buttons">
<Button wide label="Login" edges="curved" design="bo-primary" to="/login" />
<Button wide label="Register" edges="curved" design="bo-primary" to="/register" />
</section>
</Column> </Column>
</Display> </Display>
</Page> </Page>

View file

@ -1,15 +1,13 @@
import './Login.sass' import './Login.sass'
import { Logo, Link, Page, Row, Padding, Box, Radio, Combobox, Input, Button, Modal, Column } from '../../components' import { Logo, Link, Page, Row, Padding, Box, Radio, Combobox, Input, Button, Modal, Column, Display } from '../../components'
import { IoChevronBack } from 'solid-icons/io' import { IoChevronBack } from 'solid-icons/io'
import { createSignal, Show, createEffect } from 'solid-js' import { createSignal, Show, createEffect } from 'solid-js'
import { ofetch } from 'ofetch'
import { SHA1, SHA3 } from 'crypto-js' import { SHA1, SHA3 } from 'crypto-js'
import { useNavigate } from '@solidjs/router' import { useNavigate } from '@solidjs/router'
import { checkConnection } from '../../utils/functions' import { checkConnection, getApi } from '../../utils/functions'
import { _employeeId, _employeeName } from '../../stores/employee' import { _employeeId, _employeeName } from '../../stores/employee'
export default () => { export default () => {
const API = import.meta.env.VITE_BACKEND
const APPROVERNAME = import.meta.env.VITE_HEAD const APPROVERNAME = import.meta.env.VITE_HEAD
const navigate = useNavigate() const navigate = useNavigate()
const assessors = JSON.parse(sessionStorage.getItem('registered')!) const assessors = JSON.parse(sessionStorage.getItem('registered')!)
@ -29,18 +27,18 @@ export default () => {
return return
} }
const employeeid = await ofetch(API + 'get-employeeid/' + name(), { parseResponse: JSON.parse }) const employeeid = await getApi('get-employeeid', name())
const dbpassword = await ofetch(API + 'get-password/' + employeeid.result, { parseResponse: JSON.parse }) const dbpassword = await getApi('get-password', employeeid)
const hashPassword = await securePassword() const hashPassword = await securePassword()
if (dbpassword.result === '0') { if (dbpassword === '0') {
setErrorMessage('Not yet registered. Please proceed to Registration.') setErrorMessage('Not yet registered. Please proceed to Registration.')
} else { } else {
setErrorMessage('Invalid Password, Try again.') setErrorMessage('Invalid Password, Try again.')
} }
if (dbpassword.result === hashPassword) { if (dbpassword === hashPassword) {
_employeeId.set(employeeid.result) _employeeId.set(employeeid)
_employeeName.set(name()) _employeeName.set(name())
saveEmployee() saveEmployee()
setLoggedin(2) setLoggedin(2)
@ -83,83 +81,83 @@ export default () => {
return ( return (
<> <>
<Page alignment="column"> <Page alignment="column">
<Padding left={4.75} right={4.75} top={0} bottom={0}> <Display desktop tablet>
<Row content="split"> <Padding left={4.75} right={4.75} top={0} bottom={0}>
<Link to="/"> <Row content="split">
<Row content="left" gap={2}> <Link to="/">
<Logo size={200} /> <Row content="left" gap={2}>
<h1>OCBO e-Sign</h1> <Logo size={200} />
</Row> <h1>OCBO e-Sign</h1>
</Link>
<Link to="/">
<Row content="right">
<IoChevronBack size={45} />
<span class="back-button-text">Back</span>
</Row>
</Link>
</Row>
<Padding top={2} left={0} right={0} bottom={0}>
<Row>
<Box curved thickness={2} padding="2.25rem" color="#253849be" background="#04040660">
{/* <section class="box"> */}
<Row>
<span class="box-title">Login</span>
</Row> </Row>
</Link>
<Padding top={2} left={2} right={2} bottom={0}> <Link to="/">
<Row> <Row content="right">
<Radio data={roles} value={role()} onChange={setRole} gap={10} /> <IoChevronBack size={45} />
</Row> <span class="back-button-text">Back</span>
</Padding> </Row>
<h4>Name</h4> </Link>
<Show when={role() !== 'Approver'}>
<Combobox options={assessors} placeholder="Select your name" value={name()} onChange={setName} />
</Show>
<Show when={role() === 'Approver'}>
<span class="approver-name">{APPROVERNAME}</span>
</Show>
<h4>Password</h4>
<Input
isPassword
value={password()}
onChange={setPassword}
onKeyDown={(event: KeyboardEvent) => {
if (event.key === 'Enter') login()
}}
/>
<Padding top={2} left={0} right={0} bottom={0}>
<Show when={password() && name()}>
<Row>
<Button edges="curved" design="bo-primary" label="Login" wide onClick={login}></Button>
</Row>
</Show>
<Show when={!password() && name()}>
<Row>
<span class="required">Required password</span>
</Row>
</Show>
<Show when={!password() && !name()}>
<Row>
<span class="required">Required name and password</span>
</Row>
</Show>
<Show when={password() && !name()}>
<Row>
<span class="required">Required name</span>
</Row>
</Show>
</Padding>
{/* </section> */}
</Box>
</Row> </Row>
<Padding top={2} left={0} right={0} bottom={0}>
<Row>
<Box curved thickness={2} padding="2.25rem" color="#253849be" background="#04040660">
<Row>
<span class="box-title">Login</span>
</Row>
<Padding top={2} left={2} right={2} bottom={0}>
<Row>
<Radio data={roles} value={role()} onChange={setRole} gap={10} />
</Row>
</Padding>
<h4>Name</h4>
<Show when={role() !== 'Approver'}>
<Combobox options={assessors} placeholder="Select your name" value={name()} onChange={setName} />
</Show>
<Show when={role() === 'Approver'}>
<span class="approver-name">{APPROVERNAME}</span>
</Show>
<h4>Password</h4>
<Input
isPassword
value={password()}
onChange={setPassword}
onKeyDown={(event: KeyboardEvent) => {
if (event.key === 'Enter') login()
}}
/>
<Padding top={2} left={0} right={0} bottom={0}>
<Show when={password() && name()}>
<Row>
<Button edges="curved" design="bo-primary" label="Login" wide onClick={login}></Button>
</Row>
</Show>
<Show when={!password() && name()}>
<Row>
<span class="required">Required password</span>
</Row>
</Show>
<Show when={!password() && !name()}>
<Row>
<span class="required">Required name and password</span>
</Row>
</Show>
<Show when={password() && !name()}>
<Row>
<span class="required">Required name</span>
</Row>
</Show>
</Padding>
</Box>
</Row>
</Padding>
</Padding> </Padding>
</Padding> </Display>
</Page> </Page>
<div onClick={navigateToRolePage}> <div onClick={navigateToRolePage}>

View file

@ -5,7 +5,7 @@ import { Tabs } from '@kobalte/core/tabs'
import { ofetch } from 'ofetch' import { ofetch } from 'ofetch'
import { onMount, createSignal } from 'solid-js' import { onMount, createSignal } from 'solid-js'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { checkConnection, createPdf } from '../../utils/functions' import { checkConnection, getApi, getApiMulti } from '../../utils/functions'
import { FaSolidThumbsUp } from 'solid-icons/fa' import { FaSolidThumbsUp } from 'solid-icons/fa'
import { _employeeName } from '../../stores/employee' import { _employeeName } from '../../stores/employee'
import { useNavigate } from '@solidjs/router' import { useNavigate } from '@solidjs/router'
@ -51,22 +51,18 @@ export default () => {
const [employeeName, setEmployeeName] = createSignal('') const [employeeName, setEmployeeName] = createSignal('')
const getListForApproval = async () => { const getListForApproval = async () => {
try { const responseE = await getApiMulti('get-listopapproval-electrical')
const responseE = await ofetch(API + 'get-listopapproval-electrical', { parseResponse: JSON.parse }) setApplicationListElectrical(responseE.result)
setApplicationListElectrical(responseE.result) setNameListElectrical(responseE.result2)
setNameListElectrical(responseE.result2)
const responseO = await ofetch(API + 'get-listopapproval-occupancy', { parseResponse: JSON.parse }) const responseO = await getApiMulti('get-listopapproval-occupancy')
setApplicationListOccupancy(responseO.result) setApplicationListOccupancy(responseO.result)
setNameListOccupancy(responseO.result2) setNameListOccupancy(responseO.result2)
} catch (error) {
console.error(error)
}
} }
const getListForApprovalElectrical = async () => { const getListForApprovalElectrical = async () => {
try { try {
const responseE = await ofetch(API + 'get-listopapproval-electrical', { parseResponse: JSON.parse }) const responseE = await getApiMulti('get-listopapproval-electrical')
setApplicationListElectrical(responseE.result) setApplicationListElectrical(responseE.result)
setNameListElectrical(responseE.result2) setNameListElectrical(responseE.result2)
} catch (error) { } catch (error) {
@ -76,7 +72,7 @@ export default () => {
const getListForApprovalOccupancy = async () => { const getListForApprovalOccupancy = async () => {
try { try {
const responseO = await ofetch(API + 'get-listopapproval-occupancy', { parseResponse: JSON.parse }) const responseO = await getApiMulti('get-listopapproval-occupancy')
setApplicationListOccupancy(responseO.result) setApplicationListOccupancy(responseO.result)
setNameListOccupancy(responseO.result2) setNameListOccupancy(responseO.result2)
} catch (error) { } catch (error) {
@ -103,7 +99,7 @@ export default () => {
const getopdetails = async (division: string, applicationNo: string) => { const getopdetails = async (division: string, applicationNo: string) => {
if (division === 'electrical') { if (division === 'electrical') {
const op = await ofetch(API + 'get-opdetails-electrical/' + applicationNo, { parseResponse: JSON.parse }) const op = await getApiMulti('get-opdetails-electrical', applicationNo)
setAssessor(op.result7[0]) setAssessor(op.result7[0])
setLocation(op.result5[0]) setLocation(op.result5[0])
setType(op.result6[0]) setType(op.result6[0])
@ -111,7 +107,7 @@ export default () => {
setApplicationId(op.result11[0]) setApplicationId(op.result11[0])
setTotalOp(calculateTotal(op.result9)) setTotalOp(calculateTotal(op.result9))
} else if (division === 'occupancy') { } else if (division === 'occupancy') {
const op = await ofetch(API + 'get-opdetails-occupancy/' + applicationNo, { parseResponse: JSON.parse }) const op = await getApiMulti('get-opdetails-occupancy', applicationNo)
setAssessor(op.result7[0]) setAssessor(op.result7[0])
setLocation(op.result5[0]) setLocation(op.result5[0])
setType(op.result6[0]) setType(op.result6[0])
@ -126,7 +122,36 @@ export default () => {
return total return total
} }
const approveHandler = async (application: string) => { // const approveHandler = async (application: string) => {
// let signed: boolean = false
// let forprinting: boolean = false
// let updateOrderofpayment: boolean = false
// setConnected(await checkConnection())
// if (connected() === false) {
// setErrorMessage('No Connection on Server')
// return
// }
// signed = await setNewStatus('ELECTRICAL ORDER OF PAYMENT APPROVED AND SIGNED', '170', 'ELECOPAPPROVEDSIGNED', 1)
// const approvedid = await getIdByApplication(application)
// updateDocflow(approvedid, 'FOR ELECTRICAL ORDER OF PAYMENT APPROVAL')
// if (!signed) return
// forprinting = await setNewStatus('FOR ELECTRICAL ORDER OF PAYMENT PRINTING', '95', 'ELECOPPRINT', 0)
// if (!forprinting) return
// updateOrderofpayment = await updateOp()
// if (updateOrderofpayment) {
// postTransaction()
// postPops(application)
// setApprovedApplication(application)
// setApproved(true)
// }
// }
const approveHandler = async (division: string, application: string) => {
let signed: boolean = false let signed: boolean = false
let forprinting: boolean = false let forprinting: boolean = false
let updateOrderofpayment: boolean = false let updateOrderofpayment: boolean = false
@ -137,21 +162,33 @@ export default () => {
return return
} }
signed = await setNewStatus('ELECTRICAL ORDER OF PAYMENT APPROVED AND SIGNED', '170', 'ELECOPAPPROVEDSIGNED', 1) if (division === 'electrical') {
const approvedid = await getIdByApplication(application) signed = await setNewStatus('ELECTRICAL ORDER OF PAYMENT APPROVED AND SIGNED', '170', 'ELECOPAPPROVEDSIGNED', 1)
updateDocflow(approvedid, 'FOR ELECTRICAL ORDER OF PAYMENT APPROVAL') const approvedid = await getIdByApplication(application)
if (!signed) return updateDocflow(approvedid, 'FOR ELECTRICAL ORDER OF PAYMENT APPROVAL')
if (!signed) return
forprinting = await setNewStatus('FOR ELECTRICAL ORDER OF PAYMENT PRINTING', '95', 'ELECOPPRINT', 0) forprinting = await setNewStatus('FOR ELECTRICAL ORDER OF PAYMENT PRINTING', '95', 'ELECOPPRINT', 0)
if (!forprinting) return if (!forprinting) return
updateOrderofpayment = await updateOp() updateOrderofpayment = await updateOp()
if (updateOrderofpayment) { if (updateOrderofpayment) {
postTransaction() postTransaction()
postPops(application) postPops(division, application)
setApprovedApplication(application) setApprovedApplication(application)
setApproved(true) setApproved(true)
}
} else if (division === 'occupancy') {
signed = await setNewStatus('OCCUPANCY ORDER OF PAYMENT APPROVED AND SIGNED', '172', 'OCCOPAPPROVEDSIGNED', 1)
const approvedid = await getIdByApplication(application)
updateDocflow(approvedid, 'FOR OCCUPANCY RECOMMENDING APPROVAL')
if (!signed) return
forprinting = await setNewStatus('APPROVED FOR PRINTING OF BUREAU OF FIRE AND ORDER OF PAYMENT', '23', 'OCORDEROFPAYMENT', 0)
if (!forprinting) return
updateOrderofpayment = await updateOp()
} }
} }
@ -202,10 +239,15 @@ export default () => {
// _assessorid.set(employeeId()) // _assessorid.set(employeeId())
// } // }
const postPops = async (application: string) => { const postPops = async (division: string, application: string) => {
const applicationId = await ofetch(API + 'get-idbyapplication-electrical/' + application, { parseResponse: JSON.parse }) let response
const response = await ofetch(API + 'get-popsdetails-electrical/' + applicationId.result, { parseResponse: JSON.parse })
// const applicationNo = response.result[0] if (division === 'electrical') {
response = await getApiMulti('get-popsdetails-electrical', application)
} else if (division === 'occupancy') {
response = await getApiMulti('get-popsdetails-occupancy', application)
}
const customerid = response.result2[0] const customerid = response.result2[0]
const customerName = response.result3[0] const customerName = response.result3[0]
const location = response.result4[0] const location = response.result4[0]
@ -278,9 +320,8 @@ export default () => {
const geteSignId = async () => { const geteSignId = async () => {
try { try {
const response = await ofetch(API + 'get-esignid/' + ID, { parseResponse: JSON.parse }) const response = await getApi('get-esignid', ID)
const result = response.result return response
return result
} catch { } catch {
return 0 return 0
} }
@ -290,6 +331,7 @@ export default () => {
const id = await geteSignId() const id = await geteSignId()
const today = new Date() const today = new Date()
const formatedDate = dayjs(today).format('YYYY-MM-DD HH:mm:ss') const formatedDate = dayjs(today).format('YYYY-MM-DD HH:mm:ss')
await ofetch(API + 'post-esigntransaction', { await ofetch(API + 'post-esigntransaction', {
method: 'POST', method: 'POST',
body: { data: parseInt(id), data2: approvedApplication(), data3: formatedDate }, body: { data: parseInt(id), data2: approvedApplication(), data3: formatedDate },
@ -305,9 +347,8 @@ export default () => {
const getIdByApplication = async (applicationNo: string) => { const getIdByApplication = async (applicationNo: string) => {
try { try {
const response = await ofetch(API + 'get-idbyapplication-electrical/' + applicationNo, { parseResponse: JSON.parse }) const response = await getApi('get-idbyapplication-electrical', applicationNo)
const result = response.result return parseInt(response)
return parseInt(result)
} catch { } catch {
return 0 return 0
} }
@ -473,7 +514,7 @@ export default () => {
</Padding> </Padding>
<Row padding="2rem 0 0 0"> <Row padding="2rem 0 0 0">
<Button wide label="Approve" edges="curved" design="bo-primary" onClick={() => approveHandler(item)}></Button> <Button wide label="Approve" edges="curved" design="bo-primary" onClick={() => approveHandler('occupancy', item)}></Button>
<span class="modal__cancel">Click anywhere to cancel</span> <span class="modal__cancel">Click anywhere to cancel</span>
</Row> </Row>
</Padding> </Padding>
@ -560,7 +601,7 @@ export default () => {
</Padding> </Padding>
<Row padding="2rem 0 0 0"> <Row padding="2rem 0 0 0">
<Button wide label="Approve" edges="curved" design="bo-primary" onClick={() => approveHandler(item)}></Button> <Button wide label="Approve" edges="curved" design="bo-primary" onClick={() => approveHandler('electrical', item)}></Button>
<span class="modal__cancel">Click anywhere to cancel</span> <span class="modal__cancel">Click anywhere to cancel</span>
</Row> </Row>
</Padding> </Padding>

View file

@ -1,5 +1,5 @@
import './Register.sass' import './Register.sass'
import { Logo, Link, Page, Row, Padding, Combobox, Box, Button, Modal, Column, QR, Input } from '../../components' import { Logo, Link, Page, Row, Padding, Combobox, Box, Button, Modal, Column, QR, Input, Display } from '../../components'
import { IoChevronBack } from 'solid-icons/io' import { IoChevronBack } from 'solid-icons/io'
import { Show, createSignal, createEffect } from 'solid-js' import { Show, createSignal, createEffect } from 'solid-js'
import { ofetch } from 'ofetch' import { ofetch } from 'ofetch'
@ -7,6 +7,7 @@ import { SHA3, SHA1 } from 'crypto-js'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { FileField } from '@kobalte/core/file-field' import { FileField } from '@kobalte/core/file-field'
import { useNavigate } from '@solidjs/router' import { useNavigate } from '@solidjs/router'
import { checkConnection, getApi } from '../../utils/functions'
export default () => { export default () => {
const API = import.meta.env.VITE_BACKEND const API = import.meta.env.VITE_BACKEND
@ -19,31 +20,30 @@ export default () => {
const [role, setRole] = createSignal('') const [role, setRole] = createSignal('')
const [name, setName] = createSignal('') const [name, setName] = createSignal('')
const [password, setPassword] = createSignal('') const [password, setPassword] = createSignal('')
const [hashPassword, setHashPassword] = createSignal('')
const [id, setId] = createSignal<number>(0)
const [signature, setSignature] = createSignal('') const [signature, setSignature] = createSignal('')
const [saved, setSaved] = createSignal(false) const [saved, setSaved] = createSignal(false)
const [file, setFile] = createSignal<File[]>() const [file, setFile] = createSignal<File[]>()
const [base64image, setBase64image] = createSignal('') const [base64image, setBase64image] = createSignal('')
const [allow, setAllow] = createSignal(0) const [allow, setAllow] = createSignal(0)
const [connected, setConnected] = createSignal(true)
const [errorMessage, setErrorMessage] = createSignal('')
let globalId = 0
let globalHashPassword = ''
const getEmployeeId = async (val: string) => { const getEmployeeId = async (val: string) => {
try { setName(val)
setName(val) const id = await getApi('get-employeeid', val)
const id = await ofetch(API + 'get-employeeid/' + val, { parseResponse: JSON.parse }) globalId = parseInt(id)
setId(parseInt(id.result)) await checkRegistered(val)
await checkRegistered()
} catch {
setId(0)
}
} }
const generateSignature = () => { const generateSignature = () => {
if (role() === 'APPROVER') { if (role() === 'APPROVER') {
setId(276) globalId = 276
setName(APPROVERNAME) setName(APPROVERNAME)
} }
const hash = SHA3(id().toString()) const hash = SHA3(globalId.toString())
setSignature(`Use OCBO e-Sign Validator - scanid=${hash.toString()}`) setSignature(`Use OCBO e-Sign Validator - scanid=${hash.toString()}`)
try { try {
@ -56,6 +56,12 @@ export default () => {
} }
const register = async () => { const register = async () => {
setConnected(await checkConnection())
if (connected() === false) {
setErrorMessage('No Connection on Server')
return
}
await securePassword() await securePassword()
const blob = new Blob(file()) const blob = new Blob(file())
const base64 = await convertBase64(blob) const base64 = await convertBase64(blob)
@ -63,7 +69,7 @@ export default () => {
await ofetch(API + 'post-registration', { await ofetch(API + 'post-registration', {
method: 'POST', method: 'POST',
body: { data: id(), data2: hashPassword(), data3: signature(), data4: base64 }, body: { data: globalId, data2: globalHashPassword, data3: signature(), data4: base64 },
}) })
} }
@ -77,7 +83,7 @@ export default () => {
const firstHashing = SHA1(password()) const firstHashing = SHA1(password())
const secondHashing = SHA3(firstHashing) const secondHashing = SHA3(firstHashing)
const thirdHashing = SHA1(secondHashing) const thirdHashing = SHA1(secondHashing)
setHashPassword(thirdHashing.toString()) globalHashPassword = thirdHashing.toString()
} }
const convertBase64 = (blob: Blob) => { const convertBase64 = (blob: Blob) => {
@ -88,12 +94,10 @@ export default () => {
}) })
} }
const checkRegistered = async () => { const checkRegistered = async (name: string) => {
const employeeid = id()
try { try {
const registered = await ofetch(API + 'check-registered/' + employeeid, { parseResponse: JSON.parse }) const registered = await getApi('check-registered', name)
if (registered.result > 0) { if (registered > 0) {
setAllow(1) setAllow(1)
} else { } else {
setAllow(2) setAllow(2)
@ -106,13 +110,9 @@ export default () => {
const getAssessors = async (): Promise<string[]> => { const getAssessors = async (): Promise<string[]> => {
let assessorsNameList: string[] = [] let assessorsNameList: string[] = []
try { const assessors = await getApi('get-list-assessors')
const assessors = await ofetch(API + 'get-list-assessors', { parseResponse: JSON.parse }) assessorsNameList = [...assessors]
assessorsNameList = [...assessors.result] return [...assessorsNameList]
return [...assessorsNameList]
} catch {
return []
}
} }
const updateRegistered = async () => { const updateRegistered = async () => {
@ -127,8 +127,8 @@ export default () => {
createEffect(async () => { createEffect(async () => {
if (role() === 'APPROVER') { if (role() === 'APPROVER') {
try { try {
const registered = await ofetch(API + 'check-registered/' + 276, { parseResponse: JSON.parse }) const registered = await getApi('check-registered', APPROVERNAME)
if (registered.result > 0) { if (registered > 0) {
setAllow(1) setAllow(1)
} else { } else {
setAllow(2) setAllow(2)
@ -142,166 +142,168 @@ export default () => {
return ( return (
<> <>
<Page alignment="column"> <Page alignment="column">
<Padding left={4.75} right={4.75} top={0} bottom={0}> <Display desktop tablet>
<Row content="split"> <Padding left={4.75} right={4.75} top={0} bottom={0}>
<Link to="/"> <Row content="split">
<Row content="left" gap={2}> <Link to="/">
<Logo size={200} /> <Row content="left" gap={2}>
<h1>OCBO e-Sign</h1> <Logo size={200} />
</Row> <h1>OCBO e-Sign</h1>
</Link>
<Link to="/">
<Row content="right">
<IoChevronBack size={45} />
<span class="back-button-text">Back</span>
</Row>
</Link>
</Row>
<Padding top={2} left={0} right={0} bottom={0}>
<Row>
<Box curved thickness={2} padding="2.25rem" color="#253849be" background="#04040660">
<Row>
<span class="box-title">Registration</span>
</Row> </Row>
<h4>Role</h4> </Link>
<Combobox options={roles} placeholder="Select your role" value={role()} onChange={setRole} />
<Show when={role() === 'ASSESSOR'}> <Link to="/">
<h4>List of Assessors</h4> <Row content="right">
<Combobox options={assessors} placeholder="Select your name" value={name()} onChange={(val) => getEmployeeId(val!)} /> <IoChevronBack size={45} />
<span class="back-button-text">Back</span>
</Row>
</Link>
</Row>
<Padding top={2} left={0} right={0} bottom={0}>
<Row>
<Box curved thickness={2} padding="2.25rem" color="#253849be" background="#04040660">
<Row>
<span class="box-title">Registration</span>
</Row>
<h4>Role</h4>
<Combobox options={roles} placeholder="Select your role" value={role()} onChange={setRole} />
<Show when={role() === 'ASSESSOR'}>
<h4>List of Assessors</h4>
<Combobox options={assessors} placeholder="Select your name" value={name()} onChange={(val) => getEmployeeId(val!)} />
<Show when={allow() === 2}>
<h4>Password</h4>
<Input isPassword value={password()} onChange={setPassword}></Input>
<h4>Upload Signature</h4>
<FileField class="filefield" maxFiles={1} onFileAccept={(data) => setFile(data)} accept=".jpg, .jpeg, .png, .webp, .avif">
<FileField.Dropzone class="filefield__dropzone">Drag and drop or click to upload file</FileField.Dropzone>
<FileField.HiddenInput />
<FileField.ItemList class="filefield__itemList">
{() => (
<FileField.Item class="filefield__item">
<FileField.ItemPreviewImage class="filefield__itemPreviewImage" />
<FileField.ItemName class="filefield__itemName" />
<FileField.ItemSize class="filefield__itemSize" />
<FileField.ItemDeleteTrigger class="filefield__itemDeleteTrigger" onClick={() => setFile()}>
Delete
</FileField.ItemDeleteTrigger>
</FileField.Item>
)}
</FileField.ItemList>
</FileField>
<Padding top={2} bottom={0} left={0} right={0}>
<Show when={file() && password()}>
<Show when={file() && password() && password().length >= 4}>
<Row>
<Button edges="curved" design="bo-primary" label="Register" onClick={generateSignature} wide />
</Row>
</Show>
<Show when={file() && password() && password().length < 4}>
<Row>
<span class="already-registered">Password too short</span>
</Row>
</Show>
</Show>
<Show when={!file() && !password()}>
<Row>
<span class="already-registered">Required password and signature</span>
</Row>
</Show>
<Show when={file() && !password()}>
<Row>
<span class="already-registered">Required password</span>
</Row>
</Show>
<Show when={!file() && password()}>
<Row>
<span class="already-registered">Required signature</span>
</Row>
</Show>
</Padding>
</Show>
<Show when={allow() === 1}>
<Padding top={2} bottom={0} left={0} right={0}>
<Row>
<span class="already-registered">Already Registered</span>
</Row>
</Padding>
</Show>
</Show>
<Show when={role() === 'APPROVER'}>
<h4>Name of Approver</h4>
<span class="approver-name">{APPROVERNAME}</span>
<Show when={allow() === 2}>
<h4>Password</h4> <h4>Password</h4>
<Input isPassword value={password()} onChange={setPassword}></Input> <Input isPassword value={password()} onChange={setPassword}></Input>
<h4>Upload Signature</h4>
<FileField class="filefield" maxFiles={1} onFileAccept={(data) => setFile(data)} accept=".jpg, .jpeg, .png, .webp, .avif">
<FileField.Dropzone class="filefield__dropzone">Drag and drop or click to upload file</FileField.Dropzone>
<FileField.HiddenInput />
<FileField.ItemList class="filefield__itemList">
{() => (
<FileField.Item class="filefield__item">
<FileField.ItemPreviewImage class="filefield__itemPreviewImage" />
<FileField.ItemName class="filefield__itemName" />
<FileField.ItemSize class="filefield__itemSize" />
<FileField.ItemDeleteTrigger class="filefield__itemDeleteTrigger" onClick={() => setFile()}>
Delete
</FileField.ItemDeleteTrigger>
</FileField.Item>
)}
</FileField.ItemList>
</FileField>
<Padding top={2} bottom={0} left={0} right={0}> <Show when={allow() === 2}>
<Show when={file() && password()}> <h4>Upload Signature</h4>
<Show when={file() && password() && password().length >= 4}> <FileField class="filefield" maxFiles={1} onFileAccept={(data) => setFile(data)} accept=".png">
<FileField.Dropzone class="filefield__dropzone">Drag and drop or click to upload file</FileField.Dropzone>
<FileField.HiddenInput />
<FileField.ItemList class="filefield__itemList">
{() => (
<FileField.Item class="filefield__item">
<FileField.ItemPreviewImage class="filefield__itemPreviewImage" />
<FileField.ItemName class="filefield__itemName" />
<FileField.ItemSize class="filefield__itemSize" />
<FileField.ItemDeleteTrigger class="filefield__itemDeleteTrigger" onClick={() => setFile()}>
Delete
</FileField.ItemDeleteTrigger>
</FileField.Item>
)}
</FileField.ItemList>
</FileField>
<Padding top={2} bottom={0} left={0} right={0}>
<Show when={file() && password()}>
<Row> <Row>
<Button edges="curved" design="bo-primary" label="Register" onClick={generateSignature} wide /> <Button edges="curved" design="bo-primary" label="Register" onClick={generateSignature} wide />
</Row> </Row>
</Show> </Show>
<Show when={file() && password() && password().length < 4}> <Show when={file() && !password()}>
<Row> <Row>
<span class="already-registered">Password too short</span> <span class="already-registered">Required password</span>
</Row> </Row>
</Show> </Show>
</Show>
<Show when={!file() && !password()}> <Show when={!file() && password()}>
<Row> <Row>
<span class="already-registered">Required password and signature</span> <span class="already-registered">Required signature</span>
</Row> </Row>
</Show> </Show>
<Show when={file() && !password()}> <Show when={!file() && !password()}>
<Row> <Row>
<span class="already-registered">Required password</span> <span class="already-registered">Required password and signature</span>
</Row> </Row>
</Show> </Show>
</Padding>
</Show>
<Show when={!file() && password()}> <Show when={allow() === 1}>
<Padding top={2} bottom={0} left={0} right={0}>
<Row> <Row>
<span class="already-registered">Required signature</span> <span class="already-registered">Already Registered</span>
</Row> </Row>
</Show> </Padding>
</Padding> </Show>
</Show> </Show>
</Box>
<Show when={allow() === 1}> </Row>
<Padding top={2} bottom={0} left={0} right={0}> </Padding>
<Row>
<span class="already-registered">Already Registered</span>
</Row>
</Padding>
</Show>
</Show>
<Show when={role() === 'APPROVER'}>
<h4>Name of Approver</h4>
<span class="approver-name">{APPROVERNAME}</span>
<h4>Password</h4>
<Input isPassword value={password()} onChange={setPassword}></Input>
<Show when={allow() === 2}>
<h4>Upload Signature</h4>
<FileField class="filefield" maxFiles={1} onFileAccept={(data) => setFile(data)} accept=".png">
<FileField.Dropzone class="filefield__dropzone">Drag and drop or click to upload file</FileField.Dropzone>
<FileField.HiddenInput />
<FileField.ItemList class="filefield__itemList">
{() => (
<FileField.Item class="filefield__item">
<FileField.ItemPreviewImage class="filefield__itemPreviewImage" />
<FileField.ItemName class="filefield__itemName" />
<FileField.ItemSize class="filefield__itemSize" />
<FileField.ItemDeleteTrigger class="filefield__itemDeleteTrigger" onClick={() => setFile()}>
Delete
</FileField.ItemDeleteTrigger>
</FileField.Item>
)}
</FileField.ItemList>
</FileField>
<Padding top={2} bottom={0} left={0} right={0}>
<Show when={file() && password()}>
<Row>
<Button edges="curved" design="bo-primary" label="Register" onClick={generateSignature} wide />
</Row>
</Show>
<Show when={file() && !password()}>
<Row>
<span class="already-registered">Required password</span>
</Row>
</Show>
<Show when={!file() && password()}>
<Row>
<span class="already-registered">Required signature</span>
</Row>
</Show>
<Show when={!file() && !password()}>
<Row>
<span class="already-registered">Required password and signature</span>
</Row>
</Show>
</Padding>
</Show>
<Show when={allow() === 1}>
<Padding top={2} bottom={0} left={0} right={0}>
<Row>
<span class="already-registered">Already Registered</span>
</Row>
</Padding>
</Show>
</Show>
</Box>
</Row>
</Padding> </Padding>
</Padding> </Display>
</Page> </Page>
<div onClick={gotoIndex}> <div onClick={gotoIndex}>
@ -336,6 +338,28 @@ export default () => {
</Padding> </Padding>
</Modal> </Modal>
</div> </div>
<div onClick={() => setConnected(true)}>
<Modal trigger={connected() === false} background="#562020ff" color="#ffebebe6" opacity={0.8}>
<Padding top={1} bottom={1} left={4} right={4}>
<Column>
<Row>
<Box curved thickness={3} color="#ffebebe6" padding="1rem">
<h2>Connection Error</h2>
</Box>
</Row>
<Row>
<h3>{errorMessage()}</h3>
</Row>
<Row>
<span class="close-text">Click anywhere to close</span>
</Row>
</Column>
</Padding>
</Modal>
</div>
</> </>
) )
} }

View file

@ -1,6 +0,0 @@
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = import.meta.env.SUPABASE_URL
const supabaseKey = import.meta.env.SUPABASE_KEY
export const supabase = createClient(supabaseUrl, supabaseKey)

View file

@ -2,12 +2,17 @@ import { ofetch } from 'ofetch'
const API = import.meta.env.VITE_BACKEND const API = import.meta.env.VITE_BACKEND
export default async (api: string) => { export default async (api: string, value?: any) => {
try { try {
const fetch = await ofetch(API + api) let fetch
if (!value) {
fetch = await ofetch(API + api, { parseResponse: JSON.parse })
} else {
fetch = await ofetch(API + `${api}/${value}`, { parseResponse: JSON.parse })
}
const result = fetch.result const result = fetch.result
return result return result
} catch { } catch {
return false return []
} }
} }

View file

@ -0,0 +1,18 @@
import { ofetch } from 'ofetch'
const API = import.meta.env.VITE_BACKEND
export default async (api: string, value?: any) => {
let fetch
try {
if (!value) {
fetch = await ofetch(API + api, { parseResponse: JSON.parse })
} else {
fetch = await ofetch(API + `${api}/${value}`, { parseResponse: JSON.parse })
}
return fetch
} catch {
return {}
}
}

View file

@ -1,22 +0,0 @@
import { ofetch } from 'ofetch'
const API = import.meta.env.VITE_BACKEND
export default async (api: string) => {
try {
const fetchResponse = await ofetch(API + api)
const resultObject: Record<string, any> = {}
for (let i = 1; i <= 10; i++) {
const propertyName = `result${i}`
if (fetchResponse.hasOwnProperty(propertyName)) {
resultObject[propertyName] = fetchResponse[propertyName]
}
}
return resultObject
} catch {
return false
}
}

View file

@ -2,4 +2,5 @@ export { default as checkConnection } from './checkConnection'
export { default as createPdf } from './createPdf' export { default as createPdf } from './createPdf'
export { default as postApi } from './postApi' export { default as postApi } from './postApi'
export { default as getApi } from './getApi' export { default as getApi } from './getApi'
export { default as getApiMulti } from './getApiMulti'
// export { default as generateFavicon } from './generateFavicon' // export { default as generateFavicon } from './generateFavicon'