Compare commits

...

7 commits

9 changed files with 140 additions and 71 deletions

View file

@ -12,7 +12,6 @@
"@kobalte/core": "^0.13.11", "@kobalte/core": "^0.13.11",
"@solidjs-use/integrations": "^2.3.0", "@solidjs-use/integrations": "^2.3.0",
"@solidjs/router": "^0.15.3", "@solidjs/router": "^0.15.3",
"bcryptjs": "^3.0.2",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"dayjs": "^1.11.18", "dayjs": "^1.11.18",
"gsap": "^3.13.0", "gsap": "^3.13.0",
@ -24,6 +23,7 @@
"solidjs-use": "^2.3.0" "solidjs-use": "^2.3.0"
}, },
"devDependencies": { "devDependencies": {
"@nanostores/solid": "^1.1.1",
"@types/crypto-js": "^4.2.2", "@types/crypto-js": "^4.2.2",
"sass-embedded": "^1.93.2", "sass-embedded": "^1.93.2",
"typescript": "~5.8.3", "typescript": "~5.8.3",

23
pnpm-lock.yaml generated
View file

@ -17,9 +17,6 @@ importers:
'@solidjs/router': '@solidjs/router':
specifier: ^0.15.3 specifier: ^0.15.3
version: 0.15.3(solid-js@1.9.9) version: 0.15.3(solid-js@1.9.9)
bcryptjs:
specifier: ^3.0.2
version: 3.0.2
crypto-js: crypto-js:
specifier: ^4.2.0 specifier: ^4.2.0
version: 4.2.0 version: 4.2.0
@ -48,6 +45,9 @@ importers:
specifier: ^2.3.0 specifier: ^2.3.0
version: 2.3.0 version: 2.3.0
devDependencies: devDependencies:
'@nanostores/solid':
specifier: ^1.1.1
version: 1.1.1(nanostores@1.0.1)(solid-js@1.9.9)
'@types/crypto-js': '@types/crypto-js':
specifier: ^4.2.2 specifier: ^4.2.2
version: 4.2.2 version: 4.2.2
@ -481,6 +481,12 @@ packages:
peerDependencies: peerDependencies:
solid-js: ^1.8.8 solid-js: ^1.8.8
'@nanostores/solid@1.1.1':
resolution: {integrity: sha512-gF0Eat1/c3hOaklBMSVoEjcNzJc5zGk4VSg94H9LPmXYww1pxgr7zylpi3jjyxRu24c8+aYNkmRWzolAwzSA1A==}
peerDependencies:
nanostores: '>=0.9.0 <2.0.0'
solid-js: ^1.6.0
'@parcel/watcher-android-arm64@2.5.1': '@parcel/watcher-android-arm64@2.5.1':
resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
@ -828,10 +834,6 @@ packages:
resolution: {integrity: sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==} resolution: {integrity: sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==}
hasBin: true hasBin: true
bcryptjs@3.0.2:
resolution: {integrity: sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==}
hasBin: true
braces@3.0.3: braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -1759,6 +1761,11 @@ snapshots:
'@solid-primitives/utils': 6.3.2(solid-js@1.9.9) '@solid-primitives/utils': 6.3.2(solid-js@1.9.9)
solid-js: 1.9.9 solid-js: 1.9.9
'@nanostores/solid@1.1.1(nanostores@1.0.1)(solid-js@1.9.9)':
dependencies:
nanostores: 1.0.1
solid-js: 1.9.9
'@parcel/watcher-android-arm64@2.5.1': '@parcel/watcher-android-arm64@2.5.1':
optional: true optional: true
@ -2019,8 +2026,6 @@ snapshots:
baseline-browser-mapping@2.8.6: {} baseline-browser-mapping@2.8.6: {}
bcryptjs@3.0.2: {}
braces@3.0.3: braces@3.0.3:
dependencies: dependencies:
fill-range: 7.1.1 fill-range: 7.1.1

View file

@ -1,11 +1,20 @@
import './File.sass' import './File.sass'
import { FileField } from '@kobalte/core/file-field' import { FileField } from '@kobalte/core/file-field'
export default () => { interface Props {
maxFiles: number
accept: string
onFileAccept?: (files: File[]) => void
label: string
buttonText: string
onClick: () => void
}
export default (props: Props) => {
return ( return (
<> <>
<FileField class="filefield" maxFiles={1} onFileAccept={(data) => console.log('data', data)} onFileReject={(data) => console.log('data', data)} onFileChange={(data) => console.log('data', data)}> <FileField class="filefield" maxFiles={props.maxFiles} onFileAccept={props.onFileAccept} accept={props.accept}>
<FileField.Dropzone class="filefield__dropzone">Drag and drop or click to upload file</FileField.Dropzone> <FileField.Dropzone class="filefield__dropzone">{props.label}</FileField.Dropzone>
<FileField.HiddenInput /> <FileField.HiddenInput />
<FileField.ItemList class="filefield__itemList"> <FileField.ItemList class="filefield__itemList">
{() => ( {() => (
@ -13,7 +22,9 @@ export default () => {
<FileField.ItemPreviewImage class="filefield__itemPreviewImage" /> <FileField.ItemPreviewImage class="filefield__itemPreviewImage" />
<FileField.ItemName class="filefield__itemName" /> <FileField.ItemName class="filefield__itemName" />
<FileField.ItemSize class="filefield__itemSize" /> <FileField.ItemSize class="filefield__itemSize" />
<FileField.ItemDeleteTrigger class="filefield__itemDeleteTrigger">Delete</FileField.ItemDeleteTrigger> <FileField.ItemDeleteTrigger class="filefield__itemDeleteTrigger" onClick={props.onClick}>
{props.buttonText}
</FileField.ItemDeleteTrigger>
</FileField.Item> </FileField.Item>
)} )}
</FileField.ItemList> </FileField.ItemList>

View file

@ -1,39 +1,18 @@
import './Modal.sass' import './Modal.sass'
import { type JSXElement, Show } from 'solid-js' import { type JSXElement, Show } from 'solid-js'
import gsap from 'gsap'
interface Props { interface Props {
children: JSXElement children: JSXElement
background?: string background?: string
color?: string color?: string
border?: string border?: string
trigger: boolean
opacity?: number opacity?: number
} }
export default (props: Props) => { export default (props: Props) => {
let dialogRef!: HTMLDivElement
// const openHandler = () => {
// gsap.to(dialogRef, {
// duration: 0,
// display: 'flex',
// ease: 'power2.out',
// })
// }
const closeHandler = () => {
gsap.to(dialogRef, {
duration: 0,
display: 'none',
ease: 'power2.out',
})
}
return ( return (
<> <>
<Show when={props.trigger}> <div class="modal">
<div class="modal" ref={dialogRef} onClick={closeHandler}>
<Show when={props.border}> <Show when={props.border}>
<div class="modal__content" style={`background-color: ${props.background}; color: ${props.color}; border: 2px solid ${props.border}; opacity: ${props.opacity || 1}`}> <div class="modal__content" style={`background-color: ${props.background}; color: ${props.color}; border: 2px solid ${props.border}; opacity: ${props.opacity || 1}`}>
{props.children} {props.children}
@ -46,7 +25,6 @@ export default (props: Props) => {
</div> </div>
</Show> </Show>
</div> </div>
</Show>
</> </>
) )
} }

View file

@ -0,0 +1,51 @@
import './Modal.sass'
import { type JSXElement, Show, createSignal } from 'solid-js'
import Button from '../Button/Button'
interface Props {
children: JSXElement
background?: string
color?: string
border?: string
opacity?: number
label: string
edges?: 'curved' | 'rounded' | 'flat'
design?: 'bu-primary' | 'bu-link' | 'bu-info' | 'bu-success' | 'bu-warning' | 'bu-danger' | 'bu-dark' | 'bu-light' | 'bu-text' | 'bu-ghost' | 'bo-primary' | 'bo-secondary' | 'bo-success' | 'bo-danger' | 'bo-warning' | 'bo-info' | 'bo-light' | 'bo-dark' | 'bo-link'
width?: number
wide?: boolean
}
export default (props: Props) => {
const [isOpen, setIsOpen] = createSignal(false)
const openHandler = () => {
setIsOpen(true)
}
const closeHandler = () => {
setIsOpen(false)
}
return (
<>
<Show when={!isOpen()}>
<Button label={props.label} edges={props.edges} design={props.design} onClick={openHandler} />
</Show>
<Show when={isOpen()}>
<div class="modal" onClick={closeHandler}>
<Show when={props.border}>
<div class="modal__content" style={`background-color: ${props.background}; color: ${props.color}; border: 2px solid ${props.border}; opacity: ${props.opacity || 1}`}>
{props.children}
</div>
</Show>
<Show when={!props.border}>
<div class="modal__content" style={`background-color: ${props.background}; color: ${props.color}; opacity: ${props.opacity || 1}; box-shadow: 5px 4px 6px rgba(0, 0, 0, 0.5)`}>
{props.children}
</div>
</Show>
</div>
</Show>
</>
)
}

View file

@ -14,6 +14,7 @@ export { default as Row } from './Row/Row'
export { default as Display } from './Display/Display' export { default as Display } from './Display/Display'
export { default as Padding } from './Padding/Padding' export { default as Padding } from './Padding/Padding'
export { default as Modal } from './Modal/Modal' export { default as Modal } from './Modal/Modal'
export { default as ModalButton } from './Modal/ModalButton'
export { default as Table } from './Table/Table' export { default as Table } from './Table/Table'
export { default as Combobox } from './Combobox/Combobox' export { default as Combobox } from './Combobox/Combobox'
export { default as File } from './File/File' export { default as File } from './File/File'

View file

@ -1,6 +1,16 @@
@use 'sass:color'
.box-title .box-title
font-size: 1.75rem font-size: 1.75rem
font-weight: 700 font-weight: 700
.approver-name .approver-name
font-size: 1.25rem font-size: 1.25rem
.required
padding: 1rem
border-radius: 8px
background-color: color.adjust(#0D64E4, $blackness: 20%)
opacity: 0.6
width: 100%
text-align: center

View file

@ -1,7 +1,7 @@
import './Login.sass' import './Login.sass'
import { Logo, Link, Page, Row, Padding, Form, Box, Radio, Combobox, Input, Button, Modal } from '../../components' import { Logo, Link, Page, Row, Padding, Box, Radio, Combobox, Input, Button } from '../../components'
import { IoChevronBack } from 'solid-icons/io' import { IoChevronBack } from 'solid-icons/io'
import { createSignal, Show } from 'solid-js' import { createSignal, Show, createEffect } from 'solid-js'
import { ofetch } from 'ofetch' 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'
@ -9,13 +9,12 @@ import { useNavigate } from '@solidjs/router'
export default () => { export default () => {
const API = import.meta.env.VITE_BACKEND const API = import.meta.env.VITE_BACKEND
const APPROVERNAME = import.meta.env.VITE_HEAD const APPROVERNAME = import.meta.env.VITE_HEAD
const assessors = JSON.parse(sessionStorage.getItem('assessors')!) const assessors = JSON.parse(sessionStorage.getItem('registered')!)
const roles = ['Assessor', 'Approver'] const roles = ['Assessor', 'Approver']
const [role, setRole] = createSignal('') const [role, setRole] = createSignal('Assessor')
const [name, setName] = createSignal('') const [name, setName] = createSignal('')
const [password, setPassword] = createSignal('') const [password, setPassword] = createSignal('')
const [matched, setMatched] = createSignal(false)
const navigate = useNavigate() const navigate = useNavigate()
@ -24,13 +23,8 @@ export default () => {
const dbpassword = await ofetch(API + 'get-password/' + employeeid.result, { parseResponse: JSON.parse }) const dbpassword = await ofetch(API + 'get-password/' + employeeid.result, { parseResponse: JSON.parse })
const hashPassword = await securePassword() const hashPassword = await securePassword()
console.log('dbpassword', dbpassword.result)
console.log('hashPassword', hashPassword)
console.log(dbpassword.result === hashPassword)
if (dbpassword.result === hashPassword) { if (dbpassword.result === hashPassword) {
setMatched(true) navigate('/notification')
navigate('/')
} }
} }
@ -42,6 +36,11 @@ export default () => {
return thirdHashing.toString() return thirdHashing.toString()
} }
createEffect(() => {
if (role() === 'Approver') setName(APPROVERNAME)
else if (role() !== 'Approver' && name() === APPROVERNAME) setName('')
})
return ( return (
<> <>
<Page alignment="column"> <Page alignment="column">
@ -65,7 +64,14 @@ export default () => {
<Row> <Row>
<Box curved thickness={2} padding={2} color="#2f465cd7" background="#04040642"> <Box curved thickness={2} padding={2} color="#2f465cd7" background="#04040642">
<Row> <Row>
<span class="box-title">Login</span> <span
class="box-title"
onClick={() => {
console.log(name())
}}
>
Login
</span>
</Row> </Row>
<Padding top={2} left={2} right={2} bottom={0}> <Padding top={2} left={2} right={2} bottom={0}>
@ -84,18 +90,28 @@ export default () => {
<Input value={password()} onChange={setPassword}></Input> <Input value={password()} onChange={setPassword}></Input>
<Padding top={2} left={0} right={0} bottom={0}> <Padding top={2} left={0} right={0} bottom={0}>
<Show when={password() && name()}>
<Row> <Row>
<Button edges="curved" design="bo-primary" label="Login" wide onClick={login}></Button> <Button edges="curved" design="bo-primary" label="Login" wide onClick={login}></Button>
</Row> </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>
</Padding> </Padding>
</Box> </Box>
</Row> </Row>
</Padding> </Padding>
</Page> </Page>
<Modal trigger={matched()} background="#ffffffff" color="#000000e4" opacity={0.5}>
<h1>1</h1>
</Modal>
</> </>
) )
} }

View file

@ -6,7 +6,6 @@ import { ofetch } from 'ofetch'
import { SHA3, SHA1 } from 'crypto-js' 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 bcrypt from 'bcryptjs'
export default () => { export default () => {
const API = import.meta.env.VITE_BACKEND const API = import.meta.env.VITE_BACKEND
@ -71,8 +70,6 @@ export default () => {
} }
const securePassword = async () => { const securePassword = async () => {
// const salt = bcrypt.genSaltSync(9)
// const hash = bcrypt.hashSync(password(), salt)
const firstHashing = SHA1(password()) const firstHashing = SHA1(password())
const secondHashing = SHA3(firstHashing) const secondHashing = SHA3(firstHashing)
const thirdHashing = SHA1(secondHashing) const thirdHashing = SHA1(secondHashing)