fix: Homepage design

wip :Integrate quick pay for own bank
wip: Design account page as discussed
This commit is contained in:
2025-07-20 11:23:07 +05:30
parent eae989642b
commit 10a3da8949
10 changed files with 200 additions and 243 deletions

View File

@@ -162,7 +162,7 @@ export default function AccountDetails() {
</> </>
) : ( ) : (
<Group p="apart"> <Group p="apart">
<Text size="sm" fw={500} c="dimmed">Balance</Text> <Text size="sm" fw={500} c="dimmed">Available Balance</Text>
<Text size="md" c="green"> <Text size="md" c="green">
{parseFloat(accountDetails.stAvailableBalance).toLocaleString("en-IN", { {parseFloat(accountDetails.stAvailableBalance).toLocaleString("en-IN", {
minimumFractionDigits: 2, minimumFractionDigits: 2,

View File

@@ -203,7 +203,7 @@ export default function AccountStatementPage() {
<td style={{ ...cellStyle, textAlign: "left", color: txn.type === "DR" ? "#e03131" : "#2f9e44" }}> <td style={{ ...cellStyle, textAlign: "left", color: txn.type === "DR" ? "#e03131" : "#2f9e44" }}>
{parseFloat(txn.amount).toLocaleString("en-IN", { {parseFloat(txn.amount).toLocaleString("en-IN", {
minimumFractionDigits: 2, minimumFractionDigits: 2,
})} })} <span style={{fontSize:'10px'}}>{txn.type==="DR"?"Dr.":"Cr."}</span>
</td> </td>
</tr> </tr>
))} ))}

View File

@@ -105,7 +105,10 @@ export default function AccountSummary() {
<tr style={{ backgroundColor: "#3385ff" }}> <tr style={{ backgroundColor: "#3385ff" }}>
<th style={{ ...cellStyle, textAlign: "left" }}>Account Type</th> <th style={{ ...cellStyle, textAlign: "left" }}>Account Type</th>
<th style={{ ...cellStyle, textAlign: "right" }}>Account No.</th> <th style={{ ...cellStyle, textAlign: "right" }}>Account No.</th>
<th style={{ ...cellStyle, textAlign: "right" }}>Book Balance</th> {title.includes("Deposit Accounts (INR)") ?
(<th style={{ ...cellStyle, textAlign: "right" }}> Credit Book Balance</th>)
: (<th style={{ ...cellStyle, textAlign: "right" }}>Debit Book Balance</th>)}
</tr> </tr>
</thead> </thead>
<tbody>{rows}</tbody> <tbody>{rows}</tbody>

View File

@@ -4,7 +4,7 @@ import React, { useEffect, useRef, useState } from "react";
import { Button, Group, Modal, Paper, Radio, ScrollArea, Select, Stack, Text, TextInput, Title } from "@mantine/core"; import { Button, Group, Modal, Paper, Radio, ScrollArea, Select, Stack, Text, TextInput, Title } from "@mantine/core";
import { notifications } from "@mantine/notifications"; import { notifications } from "@mantine/notifications";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { generateOTP } from'@/app/OTPGenerator'; import { generateOTP } from '@/app/OTPGenerator';
interface accountData { interface accountData {
stAccountNo: string; stAccountNo: string;
@@ -94,7 +94,7 @@ export default function QuickPay() {
}, [authorized]); }, [authorized]);
async function handleValidate(){ async function handleValidate() {
if (!selectedAccNo || !beneficiaryAcc || if (!selectedAccNo || !beneficiaryAcc ||
!confirmBeneficiaryAcc !confirmBeneficiaryAcc
) { ) {
@@ -149,7 +149,7 @@ export default function QuickPay() {
} }
}; };
async function handleProceed(){ async function handleProceed() {
if (!selectedAccNo || !beneficiaryAcc || !confirmBeneficiaryAcc || !beneficiaryType || !amount || !remarks) { if (!selectedAccNo || !beneficiaryAcc || !confirmBeneficiaryAcc || !beneficiaryType || !amount || !remarks) {
notifications.show({ notifications.show({
title: "Validation Error", title: "Validation Error",
@@ -167,6 +167,16 @@ export default function QuickPay() {
}); });
return; return;
} }
if (parseInt(amount) <= 0) {
notifications.show({
title: "Invalid amount",
message: "Amount Can not be less than Zero",
color: "red",
});
return;
}
if (!showOtpField && !showTxnPassword && !showConfirmModel) { if (!showOtpField && !showTxnPassword && !showConfirmModel) {
setConfirmModel(true); setConfirmModel(true);
return; return;
@@ -218,7 +228,7 @@ export default function QuickPay() {
toAccountType: beneficiaryType, toAccountType: beneficiaryType,
amount: amount, amount: amount,
narration: remarks, narration: remarks,
tpassword:txnPassword, tpassword: txnPassword,
}), }),
}); });
const result = await res.json(); const result = await res.json();
@@ -268,7 +278,7 @@ export default function QuickPay() {
<Text><strong>Payee Account:</strong> {beneficiaryAcc}</Text> <Text><strong>Payee Account:</strong> {beneficiaryAcc}</Text>
<Text><strong>Payee Name:</strong> {beneficiaryName}</Text> <Text><strong>Payee Name:</strong> {beneficiaryName}</Text>
<Text><strong>Amount:</strong> {amount}</Text> <Text><strong>Amount:</strong> {amount}</Text>
<Text><strong>Remarks:</strong> {remarks}</Text> <Text><strong>Remarks:</strong> {remarks}</Text>
</Stack> </Stack>
<Group justify="flex-end" mt="md"> <Group justify="flex-end" mt="md">
<Button variant="default" onClick={() => setConfirmModel(false)}>Cancel</Button> <Button variant="default" onClick={() => setConfirmModel(false)}>Cancel</Button>
@@ -303,137 +313,137 @@ export default function QuickPay() {
</Radio.Group> </Radio.Group>
{bankType === "own" ? ( {bankType === "own" ? (
<div style={{ maxHeight: "320px", overflowY: "auto" }}> <div style={{ maxHeight: "320px", overflowY: "auto" }}>
<Stack gap="xs"> <Stack gap="xs">
<Group grow> <Group grow>
<Select <Select
label="Select Debit Account Number" label="Select Debit Account Number"
placeholder="Choose account number" placeholder="Choose account number"
data={accountOptions} data={accountOptions}
value={selectedAccNo} value={selectedAccNo}
onChange={setSelectedAccNo} onChange={setSelectedAccNo}
withAsterisk withAsterisk
readOnly={isVisibilityLocked} readOnly={isVisibilityLocked}
/> />
<TextInput <TextInput
label="Payee Account No" label="Payee Account No"
value={showPayeeAcc ? beneficiaryAcc : getFullMaskedAccount(beneficiaryAcc)} value={showPayeeAcc ? beneficiaryAcc : getFullMaskedAccount(beneficiaryAcc)}
onChange={(e) => { onChange={(e) => {
const value = e.currentTarget.value; const value = e.currentTarget.value;
if (/^\d*$/.test(value)) { if (/^\d*$/.test(value)) {
setBeneficiaryAcc(value); setBeneficiaryAcc(value);
setShowPayeeAcc(true); setShowPayeeAcc(true);
} }
}} }}
onBlur={() => setShowPayeeAcc(false)} onBlur={() => setShowPayeeAcc(false)}
onFocus={() => setShowPayeeAcc(true)} onFocus={() => setShowPayeeAcc(true)}
withAsterisk withAsterisk
readOnly={isVisibilityLocked} readOnly={isVisibilityLocked}
/> />
<TextInput <TextInput
label="Confirm Payee Account No" label="Confirm Payee Account No"
value={confirmBeneficiaryAcc} value={confirmBeneficiaryAcc}
onChange={(e) => { onChange={(e) => {
const value = e.currentTarget.value; const value = e.currentTarget.value;
if (/^\d*$/.test(value)) { if (/^\d*$/.test(value)) {
setConfirmBeneficiaryAcc(value); setConfirmBeneficiaryAcc(value);
} }
}} }}
// onCopy={(e) => e.preventDefault()} // onCopy={(e) => e.preventDefault()}
// onPaste={(e) => e.preventDefault()} // onPaste={(e) => e.preventDefault()}
// onCut={(e) => e.preventDefault()} // onCut={(e) => e.preventDefault()}
withAsterisk withAsterisk
readOnly={isVisibilityLocked} readOnly={isVisibilityLocked}
/> />
</Group>
<Group justify="space-between" >
<Text size="xs" c="green" style={{ visibility: selectedAccount ? "visible" : "hidden" }}>Available Balance :
{selectedAccount ? selectedAccount.stAvailableBalance : 0}
</Text>
<Group justify="center">
{validationStatus === "error" && <Text size="sm" fw={700} ta="right" c="red">{beneficiaryName}</Text>}
</Group> </Group>
<Group justify="space-between" > </Group>
<Text size="xs" c="green" style={{ visibility: selectedAccount ? "visible" : "hidden" }}>Available Balance : <Group grow>
{selectedAccount ? selectedAccount.stAvailableBalance : 0} <TextInput
</Text> label="Payee Name"
<Group justify="center"> value={validationStatus === "success" && beneficiaryName ? beneficiaryName : ""}
{validationStatus === "error" && <Text size="sm" fw={700} ta="right" c="red">{beneficiaryName}</Text>} // disabled
</Group> readOnly
</Group> />
<Group grow>
<TextInput
label="Payee Name"
value={validationStatus === "success" && beneficiaryName ? beneficiaryName : ""}
// disabled
readOnly
/>
<Select <Select
label="Beneficiary A/c Type" label="Beneficiary A/c Type"
placeholder="Select type" placeholder="Select type"
data={["Savings", "Current"]} data={["Savings", "Current"]}
value={beneficiaryType} value={beneficiaryType}
onChange={setBeneficiaryType} onChange={setBeneficiaryType}
withAsterisk withAsterisk
readOnly={showOtpField} readOnly={showOtpField}
/> />
<TextInput
label="Amount"
type="number"
value={amount}
onChange={(e) => setAmount(e.currentTarget.value)}
error={
selectedAccount && Number(amount) > Number(selectedAccount.stAvailableBalance) ?
"Amount exceeds available balance" : false}
withAsterisk
readOnly={showOtpField}
/>
<TextInput
label="Remarks"
placeholder="Enter remarks"
value={remarks}
onChange={(e) => setRemarks(e.currentTarget.value)}
withAsterisk
readOnly={showOtpField}
/>
</Group>
<Group grow>
{showOtpField && (
<TextInput <TextInput
label="Amount" label="OTP"
type="number" placeholder="Enter OTP"
value={amount} type="otp"
onChange={(e) => setAmount(e.currentTarget.value)} value={otp}
error={ onChange={(e) => setOtp(e.currentTarget.value)}
selectedAccount && Number(amount) > Number(selectedAccount.stAvailableBalance) ?
"Amount exceeds available balance" : false}
withAsterisk withAsterisk
readOnly={showOtpField} disabled={showTxnPassword}
/> />
)}
{showTxnPassword && (
<TextInput <TextInput
label="Remarks" label="Transaction Password"
placeholder="Enter remarks" placeholder="Enter transaction password"
value={remarks} type="password"
onChange={(e) => setRemarks(e.currentTarget.value)} value={txnPassword}
onChange={(e) => setTxnPassword(e.currentTarget.value)}
withAsterisk withAsterisk
readOnly={showOtpField}
/> />
</Group> )}
<Group grow> </Group>
{showOtpField && (
<TextInput
label="OTP"
placeholder="Enter OTP"
type="otp"
value={otp}
onChange={(e) => setOtp(e.currentTarget.value)}
withAsterisk
disabled={showTxnPassword}
/>
)}
{showTxnPassword && (
<TextInput
label="Transaction Password"
placeholder="Enter transaction password"
type="password"
value={txnPassword}
onChange={(e) => setTxnPassword(e.currentTarget.value)}
withAsterisk
/>
)}
</Group>
<Group justify="flex-start"> <Group justify="flex-start">
<Button variant="filled" color="blue" onClick={handleValidate} disabled={validationStatus === "success"}> <Button variant="filled" color="blue" onClick={handleValidate} disabled={validationStatus === "success"}>
Validate Validate
</Button> </Button>
<Button <Button
variant="filled" variant="filled"
color="blue" color="blue"
onClick={handleProceed} onClick={handleProceed}
loading={isSubmitting} loading={isSubmitting}
disabled={validationStatus !== "success"} disabled={validationStatus !== "success"}
> >
{!showTxnPassword && showOtpField ? "Validate the OTP" : showTxnPassword ? "Proceed to Pay" : "Proceed"} {!showTxnPassword && showOtpField ? "Validate the OTP" : showTxnPassword ? "Proceed to Pay" : "Proceed"}
</Button> </Button>
</Group> </Group>
</Stack> </Stack>
</div> </div>
) : ( ) : (
<Text size="lg" mt="md"> <Text size="lg" mt="md">
hii hii

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 97 KiB

View File

@@ -40,7 +40,7 @@ export default function CustomCarousel() {
}, [currentIndex]); }, [currentIndex]);
return ( return (
<Box style={{ position: 'relative', width: '60%', overflow: 'hidden',backgroundColor:"white" }}> <Box style={{ position: 'relative', width: '83%', overflow: 'hidden',backgroundColor:"white" }}>
{/* Scrollable container */} {/* Scrollable container */}
<Box <Box
ref={scrollRef} ref={scrollRef}

View File

@@ -93,6 +93,7 @@ export default function Login() {
return ( return (
<Providers> <Providers>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "auto", paddingTop: "5%" }}> <div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "auto", paddingTop: "5%" }}>
{/* Header */}
<Box style={{ <Box style={{
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100, position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
display: "flex", display: "flex",
@@ -121,6 +122,7 @@ export default function Login() {
</Text> </Text>
</Box> </Box>
<div style={{ marginTop: '10px' }}> <div style={{ marginTop: '10px' }}>
{/* Movable text */}
<Box <Box
style={{ style={{
width: "100%", width: "100%",
@@ -157,7 +159,9 @@ export default function Login() {
`} `}
</style> </style>
</Box> </Box>
<div style={{ display: "flex", height: "75vh", overflow: "hidden", position: "relative" }}> {/* Main */}
<div style={{ display: "flex", height: "75vh", overflow: "hidden", position: "relative",
background:'linear-gradient(to right, #02081eff, #0a3d91)' }}>
<div style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}> <div style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}>
<Image <Image
fit="cover" fit="cover"
@@ -167,120 +171,60 @@ export default function Login() {
style={{ width: "100%", height: "100%" }} style={{ width: "100%", height: "100%" }}
/> />
</div> </div>
<Card <Box w={{ base: "100%", md: "50%" }} p="lg">
shadow="lg" <Card shadow="md" padding="xl" radius="md" style={{ maxWidth: 400,margin: "0 auto",height:'68vh'}}>
padding="xl" <form onSubmit={handleLogin}>
radius="md" <TextInput
style={{ label="User ID"
flex: 1, placeholder="Enter your CIF No"
display: "flex", value={CIF}
justifyContent: "center", onInput={(e) => {
alignItems: "center", const input = e.currentTarget.value.replace(/\D/g, "");
backgroundColor: "#f0f0f0", if (input.length <= 11) SetCIF(input);
borderRadius: 0, }}
height: "100%", error={error}
boxShadow: "0 2px 10px rgba(228, 215, 215, 0.1)", required
// border:"1px solid black" />
}} <PasswordInput
> label="Password"
<Stack gap="xs" style={{ width: "100%", maxWidth: 480, marginTop: 0 }}> placeholder="Enter your password"
<Title order={6} style={{ marginLeft: 10, marginBottom: "8px" }}> value={psw}
<Text fs="italic">Welcome To KCC Bank</Text> onChange={(e) => SetPsw(e.currentTarget.value)}
<Text fw={700} style={{ fontSize: "18px", color: "#000066" }}>Internet Banking</Text> required
</Title> mt="sm"
<Box />
style={{ <Group mt="sm" align="center">
// width: 370, <Box style={{ backgroundColor: "#fff", fontSize: "18px", textDecoration: "line-through", padding: "4px 8px", fontFamily: "cursive" }}>{captcha}</Box>
marginTop: 0, <Button size="xs" variant="light" onClick={regenerateCaptcha}>Refresh</Button>
// paddingTop: 5, </Group>
padding: "10px", <TextInput
border: "1px solid #e0e0d1", label="Enter CAPTCHA"
}} placeholder="Enter above text"
> value={inputCaptcha}
<Flex justify="center" gap="md"> onChange={(e) => setInputCaptcha(e.currentTarget.value)}
<form onSubmit={handleLogin}> required
<TextInput mt="sm"
size="md" />
label="User ID" <Button type="submit" fullWidth mt="md" disabled={isLogging}>
placeholder="Enter your CIF No" {isLogging ? "Logging..." : "Login"}
type="text" </Button>
inputMode="numeric" </form>
value={CIF} </Card>
onInput={(e) => {
const input = e.currentTarget.value.replace(/\D/g, "");
if (input.length <= 11) {
SetCIF(input);
}
}}
required
error={error}
/>
<PasswordInput
label="Password"
size="md"
placeholder="Enter your password"
value={psw}
onChange={(e) => SetPsw(e.currentTarget.value)}
required
/>
<Group mt="xs" align="center" gap="xs" >
<Box
style={{
// padding: "5px",
alignItems: "center",
backgroundColor: "#fff",
fontFamily: "'UnifrakturCook',cursive",
// textDecoration: "line-through",
fontSize: "16px",
userSelect: "none",
display: "flex",
width: "30%"
}}
>
{captcha}
</Box>
<Button variant="outline" size="xs" onClick={regenerateCaptcha}>
Refresh
</Button>
</Group>
<TextInput
label="Enter CAPTCHA"
size="md"
placeholder="Enter above text"
value={inputCaptcha}
onChange={(e) => setInputCaptcha(e.currentTarget.value)}
required
/>
<Button type="submit" disabled={isLogging} fullWidth variant="filled" mt="md">
{/* Login */}
{isLogging ? "Logging...." : "Login"}
</Button>
</form>
</Flex>
</Box>
</Stack>
</Card>
{/* </div> */}
</div>
<Box style={{
width: "100%",
height: '50vh',
textAlign: "left",
marginTop: 10,
display: "flex",
// border: "1px solid blue"
}}>
<ClientCarousel />
<Box style={{ width: "40%", textAlign: "center" }}>
<Title order={2}>Security Notes :</Title>
<br></br>
<Text size="lg">When you Login,Your User Id and Password travels in an encrypted and highly secured mode .</Text>
<br></br>
<Text size="lg" fs="italic">For more information on Products and Services, Please Visit</Text>
<Text c="blue" td="underline">http://www.kccb.in/</Text>
</Box> </Box>
</Box> </div>
{/* Carousel and Notes */}
<Flex direction={{ base: "column", md: "row" }} mt="lg" p="lg">
<Box w={{ base: "100%", md: "60%" }}>
<ClientCarousel />
</Box>
<Box w={{ base: "100%", md: "40%" }} p="md" style={{ textAlign: "center" }}>
<Title order={2}>Security Notes :</Title>
<Text mt="sm" size="md">When you Login, Your User Id and Password travels in an encrypted and highly secured mode.</Text>
<Text mt="sm" fs="italic">For more information on Products and Services, Please Visit</Text>
<Anchor> http://www.kccb.in/</Anchor>
</Box>
</Flex>
{/* Footer */}
<Box <Box
component="footer" component="footer"
style={{ style={{