wip: Frontend for quick pay
This commit is contained in:
@@ -96,12 +96,12 @@ export default function AccountStatementPage() {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (end.diff(start, "day") > 60) {
|
if (end.diff(start, "day") > 90) {
|
||||||
notifications.show({
|
notifications.show({
|
||||||
withBorder: true,
|
withBorder: true,
|
||||||
color: "red",
|
color: "red",
|
||||||
title: "Invalid Date range",
|
title: "Invalid Date range",
|
||||||
message: "End date must be within 60 days from start date",
|
message: "End date must be within 90 days from start date",
|
||||||
autoClose: 4000,
|
autoClose: 4000,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@@ -1,110 +1,392 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Box,
|
|
||||||
Button,
|
Button,
|
||||||
Flex,
|
|
||||||
Group,
|
Group,
|
||||||
|
Paper,
|
||||||
Radio,
|
Radio,
|
||||||
|
ScrollArea,
|
||||||
Select,
|
Select,
|
||||||
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Title,
|
Title,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { useState } from "react";
|
import { notifications } from "@mantine/notifications";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
export default function FundTransferForm() {
|
interface accountData {
|
||||||
const [paymentMethod, setPaymentMethod] = useState("imps");
|
stAccountNo: string;
|
||||||
|
stAccountType: string;
|
||||||
|
stAvailableBalance: string;
|
||||||
|
custname: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function QuickPay() {
|
||||||
|
const router = useRouter();
|
||||||
|
const [bankType, setBankType] = useState("own");
|
||||||
|
const [authorized, setAuthorized] = useState<boolean | null>(null);
|
||||||
|
const [accountData, setAccountData] = useState<accountData[]>([]);
|
||||||
|
const [selectedAccNo, setSelectedAccNo] = useState<string | null>(null);
|
||||||
|
const [beneficiaryAcc, setBeneficiaryAcc] = useState("");
|
||||||
|
const [confirmBeneficiaryAcc, setConfirmBeneficiaryAcc] = useState("");
|
||||||
|
const [beneficiaryType, setBeneficiaryType] = useState<string | null>(null);
|
||||||
|
const [isVisibilityLocked, setIsVisibilityLocked] = useState(false);
|
||||||
|
const [amount, setAmount] = useState("");
|
||||||
|
const [remarks, setRemarks] = useState("");
|
||||||
|
const [showTxnPassword, setShowTxnPassword] = useState(false);
|
||||||
|
const [txnPassword, setTxnPassword] = useState("");
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
const [validationStatus, setValidationStatus] = useState<"success" | "error" | null>(null);
|
||||||
|
const [beneficiaryName, setBeneficiaryName] = useState<string | null>(null);
|
||||||
|
const [showOtpField, setShowOtpField] = useState(false);
|
||||||
|
const [otp, setOtp] = useState("");
|
||||||
|
|
||||||
|
const accountOptions = accountData.map((acc) => ({
|
||||||
|
value: acc.stAccountNo,
|
||||||
|
label: `${acc.stAccountNo} (${acc.stAccountType})`,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const FetchAccountDetails = async () => {
|
||||||
|
try {
|
||||||
|
const token = localStorage.getItem("access_token");
|
||||||
|
const response = await fetch("/api/customer", {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (response.ok && Array.isArray(data)) {
|
||||||
|
const filterSAaccount =data.filter((acc)=>acc.stAccountType==='SA');
|
||||||
|
setAccountData(filterSAaccount);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
notifications.show({
|
||||||
|
withBorder: true,
|
||||||
|
color: "red",
|
||||||
|
title: "Please try again later",
|
||||||
|
message: "Unable to Fetch, Please try again later",
|
||||||
|
autoClose: 5000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const token = localStorage.getItem("access_token");
|
||||||
|
if (!token) {
|
||||||
|
setAuthorized(false);
|
||||||
|
router.push("/login");
|
||||||
|
} else {
|
||||||
|
setAuthorized(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (authorized) {
|
||||||
|
FetchAccountDetails();
|
||||||
|
}
|
||||||
|
}, [authorized]);
|
||||||
|
|
||||||
|
const isValidTxnPassword = (password: string) =>
|
||||||
|
/[A-Z]/i.test(password) && /[0-9]/.test(password) && /[^a-zA-Z0-9]/.test(password);
|
||||||
|
|
||||||
|
const handleValidate = async () => {
|
||||||
|
if (!selectedAccNo || !beneficiaryAcc ||
|
||||||
|
!confirmBeneficiaryAcc
|
||||||
|
) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Validation Error",
|
||||||
|
message: "Please fill debit account, beneficiary account number and confirm beneficiary account number",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (beneficiaryAcc.length < 10 || beneficiaryAcc.length > 17) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Invalid Account Number",
|
||||||
|
message: "Please Enter valid account Number",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (beneficiaryAcc !== confirmBeneficiaryAcc) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Mismatch",
|
||||||
|
message: "Beneficiary account numbers do not match",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const token = localStorage.getItem("access_token");
|
||||||
|
const response = await fetch(`/api/beneficiary/validate/within-bank?accountNumber=${beneficiaryAcc}`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (response.ok && data?.name) {
|
||||||
|
setBeneficiaryName(data.name);
|
||||||
|
setValidationStatus("success");
|
||||||
|
setIsVisibilityLocked(true);
|
||||||
|
} else {
|
||||||
|
setBeneficiaryName("Invalid account number");
|
||||||
|
setValidationStatus("error");
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
setBeneficiaryName("Invalid account number");
|
||||||
|
setValidationStatus("error");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleProceed = async () => {
|
||||||
|
if (!selectedAccNo || !beneficiaryAcc || !confirmBeneficiaryAcc || !beneficiaryType || !amount || !remarks) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Validation Error",
|
||||||
|
message: "Please fill all required fields",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validationStatus !== "success") {
|
||||||
|
notifications.show({
|
||||||
|
title: "Validation Required",
|
||||||
|
message: "Please validate beneficiary before proceeding",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!showTxnPassword) {
|
||||||
|
setShowTxnPassword(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!txnPassword || !isValidTxnPassword(txnPassword)) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Weak Password",
|
||||||
|
message: "Password must contain letter, number, and special character",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!showOtpField) {
|
||||||
|
setShowOtpField(true);
|
||||||
|
notifications.show({
|
||||||
|
title: "OTP Sent",
|
||||||
|
message: "Check your registered device for OTP",
|
||||||
|
color: "green",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!otp) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Enter OTP",
|
||||||
|
message: "Please enter the OTP",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
setIsSubmitting(true);
|
||||||
|
const token = localStorage.getItem("access_token");
|
||||||
|
|
||||||
|
const res = await fetch("/api/payment/transfer", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
fromAccount: selectedAccNo,
|
||||||
|
toAccount: beneficiaryAcc,
|
||||||
|
toAccountType: beneficiaryType,
|
||||||
|
amount,
|
||||||
|
narration: remarks,
|
||||||
|
txnPassword,
|
||||||
|
otp,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await res.json();
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Success",
|
||||||
|
message: "Transaction successful",
|
||||||
|
color: "green",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset
|
||||||
|
setShowTxnPassword(false);
|
||||||
|
setTxnPassword("");
|
||||||
|
setShowOtpField(false);
|
||||||
|
setOtp("");
|
||||||
|
setValidationStatus(null);
|
||||||
|
setBeneficiaryName(null);
|
||||||
|
} else {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
message: result?.message || "Transaction failed",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
message: "Something went wrong",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!authorized) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Paper shadow="sm" radius="md" p="md" withBorder h={400}>
|
||||||
maw={1000}
|
<Title order={3} mb="md">
|
||||||
p="lg"
|
Quick Pay
|
||||||
w="1000px"
|
|
||||||
style={{
|
|
||||||
// borderRadius: 9,
|
|
||||||
// boxShadow: '0 0 12px rgba(0, 0, 0, 0.05)',
|
|
||||||
// backgroundColor: '#c5e4f9',
|
|
||||||
width:'150%',
|
|
||||||
marginRight: 100
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Flex
|
|
||||||
direction="column"
|
|
||||||
gap={12}
|
|
||||||
style={{ maxWidth: 1000, margin: "0 auto", padding: "1rem 0" }}
|
|
||||||
>
|
|
||||||
<Title order={4} mb={4}>
|
|
||||||
Enter Transaction Details
|
|
||||||
</Title>
|
</Title>
|
||||||
|
<Radio.Group value={bankType} onChange={setBankType} name="bankType" withAsterisk mb="md">
|
||||||
{/* Transfer From */}
|
<Group justify="center">
|
||||||
<div>
|
<Radio value="own" label="Own Bank" />
|
||||||
<Text size="sm" fw={500}>
|
<Radio value="outside" label="Outside Bank" />
|
||||||
Transfer from
|
|
||||||
</Text>
|
|
||||||
<Select
|
|
||||||
placeholder="Select account"
|
|
||||||
data={["Savings - 1234"]}
|
|
||||||
size="sm"
|
|
||||||
mt={4}
|
|
||||||
/>
|
|
||||||
{/* <Text size="xs" c="red" mt={2}>
|
|
||||||
* Total available amount is ₹ *****
|
|
||||||
</Text> */}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Amount + Remarks */}
|
|
||||||
<Group grow gap="sm">
|
|
||||||
<TextInput label="Amount" placeholder="Enter amount" size="sm" />
|
|
||||||
<TextInput
|
|
||||||
label="Remarks (optional)"
|
|
||||||
placeholder="Remarks"
|
|
||||||
size="sm"
|
|
||||||
/>
|
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{/* Payment Method */}
|
|
||||||
<div>
|
|
||||||
<Text size="sm" fw={500} mb={4}>
|
|
||||||
Payment Method
|
|
||||||
</Text>
|
|
||||||
<Radio.Group
|
|
||||||
value={paymentMethod}
|
|
||||||
onChange={setPaymentMethod}
|
|
||||||
name="payment-method"
|
|
||||||
>
|
|
||||||
<Flex direction="column" gap={4}>
|
|
||||||
<Radio
|
|
||||||
value="imps"
|
|
||||||
label="IMPS (Instant Transfer up to 2 Lakh, Available 24x7 365 Days)"
|
|
||||||
/>
|
|
||||||
<Radio
|
|
||||||
value="neft"
|
|
||||||
label="NEFT (Regular Transfer, Available 24x7 365 Days)"
|
|
||||||
/>
|
|
||||||
<Radio
|
|
||||||
value="rtgs"
|
|
||||||
label="RTGS (Transfer above 2 lakh, 7AM - 6PM on RBI Working Days)"
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* IFSC + Bank Name */}
|
{bankType === "own" ? (
|
||||||
<Group grow gap="sm">
|
<ScrollArea style={{ flex: 1 }}>
|
||||||
<TextInput label="Payee Bank IFSC" placeholder="Enter IFSC code" size="sm" />
|
<div style={{ maxHeight: "320px", overflowY: "auto" }}>
|
||||||
<TextInput label="Payee Bank Name" placeholder="Enter bank name" size="sm" />
|
<Stack gap="xs">
|
||||||
|
<Group grow>
|
||||||
|
<Select
|
||||||
|
label="Select Debit Account Number"
|
||||||
|
placeholder="Choose account number"
|
||||||
|
data={accountOptions}
|
||||||
|
value={selectedAccNo}
|
||||||
|
onChange={setSelectedAccNo}
|
||||||
|
withAsterisk
|
||||||
|
disabled={isVisibilityLocked}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label="Beneficiary Account No"
|
||||||
|
value={beneficiaryAcc}
|
||||||
|
onChange={(e) => {
|
||||||
|
const value = e.currentTarget.value;
|
||||||
|
if (/^\d*$/.test(value)) {
|
||||||
|
setBeneficiaryAcc(value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
withAsterisk
|
||||||
|
disabled={isVisibilityLocked}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label="Confirm Beneficiary Account No"
|
||||||
|
value={confirmBeneficiaryAcc}
|
||||||
|
onChange={(e) => {
|
||||||
|
const value = e.currentTarget.value;
|
||||||
|
if (/^\d*$/.test(value)) {
|
||||||
|
setConfirmBeneficiaryAcc(value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onCopy={(e) => e.preventDefault()}
|
||||||
|
onPaste={(e) => e.preventDefault()}
|
||||||
|
onCut={(e) => e.preventDefault()}
|
||||||
|
withAsterisk
|
||||||
|
disabled={isVisibilityLocked}
|
||||||
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{/* Buttons */}
|
<Group align="center" gap="sm">
|
||||||
<Group justify="flex-end" mt="sm">
|
<Button variant="filled" color="blue" onClick={handleValidate}>
|
||||||
<Button variant="default" size="sm">
|
Validate
|
||||||
Cancel
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="sm">PROCEED TO PAY</Button>
|
{validationStatus === "success" && <Text c="green">{beneficiaryName}</Text>}
|
||||||
|
{validationStatus === "error" && <Text c="red">{beneficiaryName}</Text>}
|
||||||
</Group>
|
</Group>
|
||||||
</Flex>
|
|
||||||
</Box>
|
<Group grow>
|
||||||
|
<Select
|
||||||
|
label="Beneficiary A/c Type"
|
||||||
|
placeholder="Select type"
|
||||||
|
data={["Savings", "Current"]}
|
||||||
|
value={beneficiaryType}
|
||||||
|
onChange={setBeneficiaryType}
|
||||||
|
withAsterisk
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label="Amount"
|
||||||
|
type="number"
|
||||||
|
value={amount}
|
||||||
|
onChange={(e) => setAmount(e.currentTarget.value)}
|
||||||
|
withAsterisk
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label="Remarks"
|
||||||
|
placeholder="Enter remarks"
|
||||||
|
value={remarks}
|
||||||
|
onChange={(e) => setRemarks(e.currentTarget.value)}
|
||||||
|
withAsterisk
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
{showTxnPassword && (
|
||||||
|
<TextInput
|
||||||
|
label="Transaction Password"
|
||||||
|
placeholder="Enter transaction password"
|
||||||
|
type="password"
|
||||||
|
value={txnPassword}
|
||||||
|
onChange={(e) => setTxnPassword(e.currentTarget.value)}
|
||||||
|
withAsterisk
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showOtpField && (
|
||||||
|
<TextInput
|
||||||
|
label="OTP"
|
||||||
|
placeholder="Enter OTP"
|
||||||
|
value={otp}
|
||||||
|
onChange={(e) => setOtp(e.currentTarget.value)}
|
||||||
|
withAsterisk
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Group justify="flex-start">
|
||||||
|
<Button
|
||||||
|
variant="filled"
|
||||||
|
color="blue"
|
||||||
|
onClick={handleProceed}
|
||||||
|
loading={isSubmitting}
|
||||||
|
disabled={validationStatus !== "success"}
|
||||||
|
>
|
||||||
|
{showOtpField ? "Proceed to Pay" : "Proceed"}
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
) : (
|
||||||
|
<Text size="lg" mt="md">
|
||||||
|
hii
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,13 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return data;
|
return data;
|
||||||
} else {
|
}
|
||||||
|
else if(response.status ===401 ||data.message === 'invalid or expired token'){
|
||||||
|
// console.log(data);
|
||||||
|
localStorage.removeItem("access_token");
|
||||||
|
router.push('/login');
|
||||||
|
}
|
||||||
|
else {
|
||||||
notifications.show({
|
notifications.show({
|
||||||
withBorder: true,
|
withBorder: true,
|
||||||
color: "red",
|
color: "red",
|
||||||
|
73
src/app/(main)/settings/layout.tsx
Normal file
73
src/app/(main)/settings/layout.tsx
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
"use client";
|
||||||
|
import { Divider, Stack, Text } from '@mantine/core';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const [authorized, SetAuthorized] = useState<boolean | null>(null);
|
||||||
|
const router = useRouter();
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
const links = [
|
||||||
|
{ label: "View Profile", href: "/settings" },
|
||||||
|
{ label: "Change Login Password", href: "/settings/change_login_password" },
|
||||||
|
{ label: "Change transaction Password", href: "/settings/change_transaction_password" },
|
||||||
|
{ label: "Set transaction Password", href: "/settings/set_transaction_password" },
|
||||||
|
];
|
||||||
|
useEffect(() => {
|
||||||
|
const token = localStorage.getItem("access_token");
|
||||||
|
if (!token) {
|
||||||
|
SetAuthorized(false);
|
||||||
|
router.push("/login");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SetAuthorized(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (authorized) {
|
||||||
|
return (
|
||||||
|
<div style={{ display: "flex", height: '100%' }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: "16%",
|
||||||
|
backgroundColor: '#c5e4f9',
|
||||||
|
borderRight: "1px solid #ccc",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack style={{ background: '#228be6', height: '10%', alignItems: 'center' }}>
|
||||||
|
<Text fw={700} fs="italic" c='white' style={{ textAlign: 'center', marginTop: '10px' }}>
|
||||||
|
Settings
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Stack gap="sm" justify="flex-start" style={{ padding: '1rem' }}>
|
||||||
|
{links.map(link => {
|
||||||
|
const isActive = pathname === link.href;
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
key={link.href}
|
||||||
|
component={Link}
|
||||||
|
href={link.href}
|
||||||
|
c={isActive ? 'darkblue' : 'blue'}
|
||||||
|
style={{
|
||||||
|
textDecoration: isActive ? 'underline' : 'none',
|
||||||
|
fontWeight: isActive ? 600 : 400,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{link.label}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ flex: 1, padding: '1rem' }}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
11
src/app/(main)/settings/page.tsx
Normal file
11
src/app/(main)/settings/page.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"use client";
|
||||||
|
import { Divider, Stack, Text } from '@mantine/core';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export default function settings() {
|
||||||
|
return(
|
||||||
|
<Text>Hii</Text>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
@@ -1,22 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { Box, Grid } from "@mantine/core"
|
|
||||||
|
|
||||||
export default function Layout({
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode
|
|
||||||
}) {
|
|
||||||
return <Grid bg="gray">
|
|
||||||
<Grid.Col span={3}>
|
|
||||||
<Box bg="blue">
|
|
||||||
<p>Test Layout</p>
|
|
||||||
</Box>
|
|
||||||
</Grid.Col>
|
|
||||||
<Grid.Col span={9}>
|
|
||||||
<Box bg="yellow">
|
|
||||||
{children}
|
|
||||||
</Box>
|
|
||||||
</Grid.Col>
|
|
||||||
</Grid>
|
|
||||||
}
|
|
@@ -1,3 +0,0 @@
|
|||||||
export default function Page() {
|
|
||||||
return <p>Test Page 1</p>
|
|
||||||
}
|
|
@@ -1,3 +0,0 @@
|
|||||||
export default function Page() {
|
|
||||||
return <p>Test Page 2</p>
|
|
||||||
}
|
|
Reference in New Issue
Block a user