Added Edit Uder in Admin
This commit is contained in:
parent
2864bf8cdc
commit
fc4be718f7
66
payment-iq/app/api/dashboard/admin/users/route.ts
Normal file
66
payment-iq/app/api/dashboard/admin/users/route.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// app/api/user/route.ts
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
return NextResponse.json([
|
||||||
|
{
|
||||||
|
merchantId: 100987998,
|
||||||
|
id: "bc6a8a55-13bc-4538-8255-cd0cec3bb4e9",
|
||||||
|
mame: "Jacob",
|
||||||
|
username: "lspaddy",
|
||||||
|
firstName: "Paddy",
|
||||||
|
lastName: "Man",
|
||||||
|
email: "patrick@omegasys.eu",
|
||||||
|
phone: "",
|
||||||
|
jobTitle: "",
|
||||||
|
enabled: true,
|
||||||
|
authorities: [
|
||||||
|
"ROLE_IIN",
|
||||||
|
"ROLE_FIRST_APPROVER",
|
||||||
|
"ROLE_RULES_ADMIN",
|
||||||
|
"ROLE_TRANSACTION_VIEWER",
|
||||||
|
"ROLE_IIN_ADMIN",
|
||||||
|
"ROLE_USER_PSP_ACCOUNT",
|
||||||
|
],
|
||||||
|
allowedMerchantIds: [100987998],
|
||||||
|
created: "2025-05-04T15:32:48.432Z",
|
||||||
|
disabledBy: null,
|
||||||
|
disabledDate: null,
|
||||||
|
disabledReason: null,
|
||||||
|
incidentNotes: false,
|
||||||
|
lastLogin: "",
|
||||||
|
lastMandatoryUpdated: "2025-05-04T15:32:48.332Z",
|
||||||
|
marketingNewsletter: false,
|
||||||
|
releaseNotes: false,
|
||||||
|
requiredActions: ["CONFIGURE_TOTP", "UPDATE_PASSWORD"],
|
||||||
|
twoFactorCondition: "required",
|
||||||
|
twoFactorCredentials: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
merchantId: 100987998,
|
||||||
|
mame: "Jacob",
|
||||||
|
id: "382eed15-1e21-41fa-b1f3-0c1adb3af714",
|
||||||
|
username: "lsterence",
|
||||||
|
firstName: "Terence",
|
||||||
|
lastName: "User",
|
||||||
|
email: "terence@omegasys.eu",
|
||||||
|
phone: "",
|
||||||
|
jobTitle: "",
|
||||||
|
enabled: true,
|
||||||
|
authorities: ["ROLE_IIN", "ROLE_FIRST_APPROVER", "ROLE_RULES_ADMIN"],
|
||||||
|
allowedMerchantIds: [100987998],
|
||||||
|
created: "2025-05-04T15:32:48.432Z",
|
||||||
|
disabledBy: null,
|
||||||
|
disabledDate: null,
|
||||||
|
disabledReason: null,
|
||||||
|
incidentNotes: false,
|
||||||
|
lastLogin: "",
|
||||||
|
lastMandatoryUpdated: "2025-05-04T15:32:48.332Z",
|
||||||
|
marketingNewsletter: false,
|
||||||
|
releaseNotes: false,
|
||||||
|
requiredActions: ["CONFIGURE_TOTP", "UPDATE_PASSWORD"],
|
||||||
|
twoFactorCondition: "required",
|
||||||
|
twoFactorCredentials: [],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
@ -1,25 +1,25 @@
|
|||||||
import { transactionDummyData } from '@/app/features/Pages/transactions/mockData';
|
import { transactionDummyData } from "@/app/components/test/test2";
|
||||||
import { NextRequest, NextResponse } from 'next/server';
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
const { searchParams } = new URL(request.url);
|
const { searchParams } = new URL(request.url);
|
||||||
|
|
||||||
const state = searchParams.get('state');
|
const state = searchParams.get("state");
|
||||||
const user = searchParams.get('user');
|
const user = searchParams.get("user");
|
||||||
|
|
||||||
let filteredTransactions = [...transactionDummyData];
|
let filteredTransactions = [...transactionDummyData];
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
filteredTransactions = filteredTransactions.filter(
|
filteredTransactions = filteredTransactions.filter(
|
||||||
tx => tx.user.toString() === user
|
(tx) => tx.user.toString() === user
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
filteredTransactions = filteredTransactions.filter(
|
filteredTransactions = filteredTransactions.filter(
|
||||||
tx => tx.state.toLowerCase() === state.toLowerCase()
|
(tx) => tx.state.toLowerCase() === state.toLowerCase()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json(filteredTransactions);
|
return NextResponse.json(filteredTransactions);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,28 +1,62 @@
|
|||||||
// app/transactions/page.tsx
|
// app/transactions/page.tsx
|
||||||
'use client';
|
"use client";
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
|
|
||||||
|
// mocks/transactionData.ts
|
||||||
|
export const transactionDummyData = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
merchandId: 100987998,
|
||||||
|
transactionID: 1049131973,
|
||||||
|
user: 1,
|
||||||
|
created: "2025-06-18 10:10:30",
|
||||||
|
state: "FAILED",
|
||||||
|
statusDescription: "ERR_ABOVE_LIMIT",
|
||||||
|
pspStatusCode: 100501,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
merchandId: 100987998,
|
||||||
|
transactionID: 1049131973,
|
||||||
|
user: 2,
|
||||||
|
created: "2025-06-18 10:10:30",
|
||||||
|
state: "FAILED",
|
||||||
|
statusDescription: "ERR_ABOVE_LIMIT",
|
||||||
|
pspStatusCode: 100501,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
merchandId: 100987998,
|
||||||
|
transactionID: 1049131973,
|
||||||
|
user: 3,
|
||||||
|
created: "2025-06-18 10:10:30",
|
||||||
|
state: "FAILED",
|
||||||
|
statusDescription: "ERR_ABOVE_LIMIT",
|
||||||
|
pspStatusCode: 100501,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default function TransactionsPage() {
|
export default function TransactionsPage() {
|
||||||
const [userId, setUserId] = useState('');
|
const [userId, setUserId] = useState("");
|
||||||
const [state, setState] = useState('');
|
const [state, setState] = useState("");
|
||||||
const [statusCode, setStatusCode] = useState('');
|
const [statusCode, setStatusCode] = useState("");
|
||||||
const [transactions, setTransactions] = useState<any[]>([]);
|
const [transactions, setTransactions] = useState<any[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const fetchTransactions = async () => {
|
const fetchTransactions = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const url = new URL('https://api.example.com/transactions');
|
const url = new URL("https://api.example.com/transactions");
|
||||||
if (userId) url.searchParams.append('userId', userId);
|
if (userId) url.searchParams.append("userId", userId);
|
||||||
if (state) url.searchParams.append('state', state);
|
if (state) url.searchParams.append("state", state);
|
||||||
if (statusCode) url.searchParams.append('statusCode', statusCode);
|
if (statusCode) url.searchParams.append("statusCode", statusCode);
|
||||||
|
|
||||||
const response = await fetch(url.toString());
|
const response = await fetch(url.toString());
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setTransactions(data.transactions);
|
setTransactions(data.transactions);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching transactions:', error);
|
console.error("Error fetching transactions:", error);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@ -31,7 +65,7 @@ export default function TransactionsPage() {
|
|||||||
return (
|
return (
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<h1 className="text-xl font-bold mb-4">Transaction Search</h1>
|
<h1 className="text-xl font-bold mb-4">Transaction Search</h1>
|
||||||
|
|
||||||
<div className="flex gap-4 mb-4">
|
<div className="flex gap-4 mb-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm mb-1">User ID</label>
|
<label className="block text-sm mb-1">User ID</label>
|
||||||
@ -72,7 +106,7 @@ export default function TransactionsPage() {
|
|||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="bg-blue-500 text-white px-4 py-2 rounded text-sm"
|
className="bg-blue-500 text-white px-4 py-2 rounded text-sm"
|
||||||
>
|
>
|
||||||
{loading ? 'Loading...' : 'Search'}
|
{loading ? "Loading..." : "Search"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -104,86 +138,49 @@ export default function TransactionsPage() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-center py-4 text-sm">
|
<div className="text-center py-4 text-sm">
|
||||||
{loading ? 'Loading transactions...' : 'No transactions found'}
|
{loading ? "Loading transactions..." : "No transactions found"}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// mocks/handlers.ts
|
// mocks/handlers.ts
|
||||||
import { http, HttpResponse } from 'msw';
|
import { http, HttpResponse } from "msw";
|
||||||
import { transactionDummyData } from './transactionData';
|
|
||||||
|
|
||||||
export const handlers = [
|
export const handlers = [
|
||||||
http.get('https://api.example.com/transactions', ({ request }) => {
|
http.get("https://api.example.com/transactions", ({ request }) => {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
|
|
||||||
// Get query parameters
|
// Get query parameters
|
||||||
const userId = url.searchParams.get('userId');
|
const userId = url.searchParams.get("userId");
|
||||||
const state = url.searchParams.get('state');
|
const state = url.searchParams.get("state");
|
||||||
const statusCode = url.searchParams.get('statusCode');
|
const statusCode = url.searchParams.get("statusCode");
|
||||||
|
|
||||||
// Filter transactions based on query parameters
|
// Filter transactions based on query parameters
|
||||||
let filteredTransactions = [...transactionDummyData];
|
let filteredTransactions = [...transactionDummyData];
|
||||||
|
|
||||||
if (userId) {
|
if (userId) {
|
||||||
filteredTransactions = filteredTransactions.filter(
|
filteredTransactions = filteredTransactions.filter(
|
||||||
tx => tx.user.toString() === userId
|
(tx) => tx.user.toString() === userId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
filteredTransactions = filteredTransactions.filter(
|
filteredTransactions = filteredTransactions.filter(
|
||||||
tx => tx.state.toLowerCase() === state.toLowerCase()
|
(tx) => tx.state.toLowerCase() === state.toLowerCase()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statusCode) {
|
if (statusCode) {
|
||||||
filteredTransactions = filteredTransactions.filter(
|
filteredTransactions = filteredTransactions.filter(
|
||||||
tx => tx.pspStatusCode.toString() === statusCode
|
(tx) => tx.pspStatusCode.toString() === statusCode
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
transactions: filteredTransactions,
|
transactions: filteredTransactions,
|
||||||
count: filteredTransactions.length
|
count: filteredTransactions.length,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
// mocks/transactionData.ts
|
|
||||||
export const transactionDummyData = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
merchandId: 100987998,
|
|
||||||
transactionID: 1049131973,
|
|
||||||
user: 1,
|
|
||||||
created: "2025-06-18 10:10:30",
|
|
||||||
state: "FAILED",
|
|
||||||
statusDescription: "ERR_ABOVE_LIMIT",
|
|
||||||
pspStatusCode: 100501,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
merchandId: 100987998,
|
|
||||||
transactionID: 1049131973,
|
|
||||||
user: 2,
|
|
||||||
created: "2025-06-18 10:10:30",
|
|
||||||
state: "FAILED",
|
|
||||||
statusDescription: "ERR_ABOVE_LIMIT",
|
|
||||||
pspStatusCode: 100501,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
merchandId: 100987998,
|
|
||||||
transactionID: 1049131973,
|
|
||||||
user: 3,
|
|
||||||
created: "2025-06-18 10:10:30",
|
|
||||||
state: "FAILED",
|
|
||||||
statusDescription: "ERR_ABOVE_LIMIT",
|
|
||||||
pspStatusCode: 100501,
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
// This ensures this component is rendered only on the client side
|
|
||||||
"use client";
|
|
||||||
|
|
||||||
import Users from "@/app/features/Pages/Admin/Users/users";
|
import Users from "@/app/features/Pages/Admin/Users/users";
|
||||||
|
|
||||||
export default function BackOfficeUsersPage() {
|
export default async function BackOfficeUsersPage() {
|
||||||
|
const res = await fetch("http://localhost:3000/api/dashboard/admin/users", {
|
||||||
|
cache: "no-store", // 👈 disables caching for SSR freshness
|
||||||
|
});
|
||||||
|
const users = await res.json();
|
||||||
|
|
||||||
|
console.log("[USERS]", users);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Users />
|
<Users users={users} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,92 +1,17 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import React, { useEffect, useState } from "react";
|
import React from "react";
|
||||||
import { Card, CardContent, Typography, Chip, Stack } from "@mui/material";
|
import { Card, CardContent, Typography, Stack } from "@mui/material";
|
||||||
import { IUser } from "./interfaces";
|
import { IUser } from "./interfaces";
|
||||||
import UserRoleCard from "@/app/features/UserRoles/userRoleCard";
|
import UserRoleCard from "@/app/features/UserRoles/UserRoleCard";
|
||||||
|
|
||||||
const Users = () => {
|
interface UsersProps {
|
||||||
const [data, setData] = useState([
|
users: IUser[];
|
||||||
{
|
}
|
||||||
merchantId: 100987998,
|
|
||||||
id: "bc6a8a55-13bc-4538-8255-cd0cec3bb4e9",
|
|
||||||
mame: "Jacob",
|
|
||||||
username: "lspaddy",
|
|
||||||
firstName: "Paddy",
|
|
||||||
lastName: "Man",
|
|
||||||
email: "patrick@omegasys.eu",
|
|
||||||
phone: "",
|
|
||||||
jobTitle: "",
|
|
||||||
enabled: true,
|
|
||||||
authorities: [
|
|
||||||
"ROLE_IIN",
|
|
||||||
"ROLE_FIRST_APPROVER",
|
|
||||||
"ROLE_RULES_ADMIN",
|
|
||||||
"ROLE_TRANSACTION_VIEWER",
|
|
||||||
"ROLE_IIN_ADMIN",
|
|
||||||
"ROLE_USER_PSP_ACCOUNT",
|
|
||||||
],
|
|
||||||
allowedMerchantIds: [100987998],
|
|
||||||
created: "2025-05-04T15:32:48.432Z",
|
|
||||||
disabledBy: null,
|
|
||||||
disabledDate: null,
|
|
||||||
disabledReason: null,
|
|
||||||
incidentNotes: false,
|
|
||||||
lastLogin: "",
|
|
||||||
lastMandatoryUpdated: "2025-05-04T15:32:48.332Z",
|
|
||||||
marketingNewsletter: false,
|
|
||||||
releaseNotes: false,
|
|
||||||
requiredActions: ["CONFIGURE_TOTP", "UPDATE_PASSWORD"],
|
|
||||||
twoFactorCondition: "required",
|
|
||||||
twoFactorCredentials: [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
merchantId: 100987998,
|
|
||||||
mame: "Jacob",
|
|
||||||
id: "382eed15-1e21-41fa-b1f3-0c1adb3af714",
|
|
||||||
username: "lsterence",
|
|
||||||
firstName: "Terence",
|
|
||||||
lastName: "User",
|
|
||||||
email: "terence@omegasys.eu",
|
|
||||||
phone: "",
|
|
||||||
jobTitle: "",
|
|
||||||
enabled: true,
|
|
||||||
authorities: ["ROLE_IIN", "ROLE_FIRST_APPROVER", "ROLE_RULES_ADMIN"],
|
|
||||||
allowedMerchantIds: [100987998],
|
|
||||||
created: "2025-05-04T15:32:48.432Z",
|
|
||||||
disabledBy: null,
|
|
||||||
disabledDate: null,
|
|
||||||
disabledReason: null,
|
|
||||||
incidentNotes: false,
|
|
||||||
lastLogin: "",
|
|
||||||
lastMandatoryUpdated: "2025-05-04T15:32:48.332Z",
|
|
||||||
marketingNewsletter: false,
|
|
||||||
releaseNotes: false,
|
|
||||||
requiredActions: ["CONFIGURE_TOTP", "UPDATE_PASSWORD"],
|
|
||||||
twoFactorCondition: "required",
|
|
||||||
twoFactorCredentials: [],
|
|
||||||
},
|
|
||||||
// Add more users if needed
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Only run MSW in the browser environment
|
|
||||||
if (typeof window !== "undefined") {
|
|
||||||
const fetchData = async () => {
|
|
||||||
const response = await fetch(
|
|
||||||
"https://test-bo.paymentiq.io/paymentiq/backoffice/api/v2/users/?includeSubMids=false&size=20&page=0&merchantId=100987998"
|
|
||||||
); // This would be intercepted by MSW in the browser
|
|
||||||
const data = await response.json();
|
|
||||||
console.log("[DATA]", data);
|
|
||||||
// setData(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchData();
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
|
const Users: React.FC<UsersProps> = ({ users }) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{data.map((user: IUser) => (
|
{users.map((user: IUser) => (
|
||||||
<Card key={user.id} sx={{ mb: 2 }}>
|
<Card key={user.id} sx={{ mb: 2 }}>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Typography variant="h6">{user.username}</Typography>
|
<Typography variant="h6">{user.username}</Typography>
|
||||||
@ -103,7 +28,7 @@ const Users = () => {
|
|||||||
isAdmin={true}
|
isAdmin={true}
|
||||||
lastLogin="small"
|
lastLogin="small"
|
||||||
roles={user.authorities}
|
roles={user.authorities}
|
||||||
// merchants={Numberuser.allowedMerchantIds}
|
merchants={[]} // merchants={Numberuser.allowedMerchantIds}
|
||||||
/>
|
/>
|
||||||
{/* Add more chips or UI elements for other data */}
|
{/* Add more chips or UI elements for other data */}
|
||||||
</Stack>
|
</Stack>
|
||||||
@ -113,19 +38,4 @@ const Users = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fetch data server-side using getServerSideProps
|
|
||||||
// export async function getServerSideProps() {
|
|
||||||
// // Replace this with your actual API call
|
|
||||||
// const res = await fetch("https://api.example.com/users");
|
|
||||||
// const data = await res.json();
|
|
||||||
|
|
||||||
// // Return the fetched data as props
|
|
||||||
// return {
|
|
||||||
// props: {
|
|
||||||
// result: data, // Assuming data is an array of users
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
export default Users;
|
export default Users;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
"use client";
|
||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
import { GeneralHealthCard } from "../../GeneralHealthCard/GeneralHealthCard";
|
import { GeneralHealthCard } from "../../GeneralHealthCard/GeneralHealthCard";
|
||||||
import { TransactionsWaitingApproval } from "../../TransactionsWaitingApproval/TransactionsWaitingApproval";
|
import { TransactionsWaitingApproval } from "../../TransactionsWaitingApproval/TransactionsWaitingApproval";
|
||||||
@ -6,53 +7,8 @@ import { Documentation } from "../../Documentation/Documentation";
|
|||||||
import { AccountIQ } from "../../AccountIQ/AccountIQ";
|
import { AccountIQ } from "../../AccountIQ/AccountIQ";
|
||||||
import { WhatsNew } from "../../WhatsNew/WhatsNew";
|
import { WhatsNew } from "../../WhatsNew/WhatsNew";
|
||||||
import { TransactionsOverView } from "../../TransactionsOverview/TransactionsOverview";
|
import { TransactionsOverView } from "../../TransactionsOverview/TransactionsOverview";
|
||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
export const DashboardHomePage = () => {
|
export const DashboardHomePage = () => {
|
||||||
// useEffect to fetch data when the component mounts
|
|
||||||
useEffect(() => {
|
|
||||||
// Construct the URL with query parameters
|
|
||||||
const url =
|
|
||||||
"https://test-bo.paymentiq.io/paymentiq/backoffice/api/v2/metrics/txsummary?merchantId=100987998&fromDate=2025-06-29+19%3A10&toDate=2025-07-01+19%3A09";
|
|
||||||
|
|
||||||
// Perform the fetch request inside useEffect
|
|
||||||
const fetchData = async () => {
|
|
||||||
try {
|
|
||||||
// Start loading
|
|
||||||
|
|
||||||
// Make the API request
|
|
||||||
const response = await fetch(url, {
|
|
||||||
method: "GET", // You can change this to 'POST' if necessary
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
// Add any other headers you need here
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check if the response is OK (status code 200-299)
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`Failed to fetch: ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the JSON response
|
|
||||||
const data = await response.json();
|
|
||||||
console.log("[DATA]", data);
|
|
||||||
|
|
||||||
// Update the state with the fetched data
|
|
||||||
// setTransactions(data.result || []);
|
|
||||||
} catch (err) {
|
|
||||||
// Handle any errors that occurred during the fetch
|
|
||||||
// setError("Failed to load data, please try again.");
|
|
||||||
console.error("Fetch error:", err);
|
|
||||||
} finally {
|
|
||||||
// Set loading to false when the request is complete
|
|
||||||
// setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Call the fetch function
|
|
||||||
fetchData();
|
|
||||||
}, []); // Empty dependency
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box sx={{ p: 2 }}>
|
<Box sx={{ p: 2 }}>
|
||||||
|
|||||||
@ -28,7 +28,6 @@ import SearchFilters from "@/app/components/searchFilter/SearchFilters";
|
|||||||
const paginationModel = { page: 0, pageSize: 50 };
|
const paginationModel = { page: 0, pageSize: 50 };
|
||||||
|
|
||||||
export default function TransactionTable() {
|
export default function TransactionTable() {
|
||||||
|
|
||||||
const [form, setForm] = useState({
|
const [form, setForm] = useState({
|
||||||
keyword: "",
|
keyword: "",
|
||||||
transactionID: "",
|
transactionID: "",
|
||||||
@ -80,7 +79,9 @@ export default function TransactionTable() {
|
|||||||
const [onlyCurrentTable, setOnlyCurrentTable] = useState(false);
|
const [onlyCurrentTable, setOnlyCurrentTable] = useState(false);
|
||||||
|
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
const exportRows = onlyCurrentTable ? transactions.slice(0, 5) : transactions;
|
const exportRows = onlyCurrentTable
|
||||||
|
? transactions.slice(0, 5)
|
||||||
|
: transactions;
|
||||||
const exportData = [
|
const exportData = [
|
||||||
columns.map((col) => col.headerName),
|
columns.map((col) => col.headerName),
|
||||||
...exportRows.map((row) => columns.map((col) => row[col.field] ?? "")),
|
...exportRows.map((row) => columns.map((col) => row[col.field] ?? "")),
|
||||||
@ -103,7 +104,6 @@ export default function TransactionTable() {
|
|||||||
setOpen(false);
|
setOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const [transactions, setTransactions] = useState<any[]>([]);
|
const [transactions, setTransactions] = useState<any[]>([]);
|
||||||
|
|
||||||
const fetchTransactions = async () => {
|
const fetchTransactions = async () => {
|
||||||
@ -113,33 +113,27 @@ export default function TransactionTable() {
|
|||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
setTransactions(data);
|
setTransactions(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching transactions:', error);
|
console.error("Error fetching transactions:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchTransactions();
|
fetchTransactions();
|
||||||
}, [form]);
|
}, [form]);
|
||||||
|
|
||||||
const handleDeleteFilter = (key) => {
|
const handleDeleteFilter = (key) => {
|
||||||
setForm((prev) => ({ ...prev, [key]: '' }));
|
setForm((prev) => ({ ...prev, [key]: "" }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClearAll = () => {
|
const handleClearAll = () => {
|
||||||
resetForm()
|
resetForm();
|
||||||
fetchTransactions()
|
fetchTransactions();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleClickField = (field: string, value: any) => {
|
const handleClickField = (field: string, value: any) => {
|
||||||
setForm((prev) => ({ ...prev, [field]: value }));
|
setForm((prev) => ({ ...prev, [field]: value }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledPaper>
|
<StyledPaper>
|
||||||
<Stack
|
<Stack
|
||||||
@ -157,7 +151,11 @@ export default function TransactionTable() {
|
|||||||
sx={{ width: 300 }}
|
sx={{ width: 300 }}
|
||||||
/>
|
/>
|
||||||
<AdvancedSearch form={form} resetForm={resetForm} setForm={setForm} />
|
<AdvancedSearch form={form} resetForm={resetForm} setForm={setForm} />
|
||||||
<SearchFilters filters={form} onDeleteFilter={handleDeleteFilter} onClearAll={handleClearAll} />
|
<SearchFilters
|
||||||
|
filters={form}
|
||||||
|
onDeleteFilter={handleDeleteFilter}
|
||||||
|
onClearAll={handleClearAll}
|
||||||
|
/>
|
||||||
{/* <RightTemporaryDrawer /> */}
|
{/* <RightTemporaryDrawer /> */}
|
||||||
{/* <SearchFilterForm /> */}
|
{/* <SearchFilterForm /> */}
|
||||||
<Button
|
<Button
|
||||||
@ -174,15 +172,14 @@ export default function TransactionTable() {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
initialState={{ pagination: { paginationModel } }}
|
initialState={{ pagination: { paginationModel } }}
|
||||||
pageSizeOptions={[50, 100]}
|
pageSizeOptions={[50, 100]}
|
||||||
sx={{ border: 0, cursor: 'pointer' }}
|
sx={{ border: 0, cursor: "pointer" }}
|
||||||
|
|
||||||
onCellClick={(params, event) => {
|
onCellClick={(params, event) => {
|
||||||
// Check if the click is on a specific column
|
// Check if the click is on a specific column
|
||||||
// Do something when this specific column is clicked
|
// Do something when this specific column is clicked
|
||||||
handleClickField(params.field, params.value)
|
handleClickField(params.field, params.value);
|
||||||
console.log('Clicked cell value:', params.value); // The cell's value
|
console.log("Clicked cell value:", params.value); // The cell's value
|
||||||
console.log('Column field:', params.field); // The column's field name (from your columns definition)
|
console.log("Column field:", params.field); // The column's field name (from your columns definition)
|
||||||
console.log('Column header:', params.colDef.headerName); // The column's display name // Your custom logic here
|
console.log("Column header:", params.colDef.headerName); // The column's display name // Your custom logic here
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
46
payment-iq/app/features/UserRoles/AddUser/AddUser.scss
Normal file
46
payment-iq/app/features/UserRoles/AddUser/AddUser.scss
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
.edit-user {
|
||||||
|
margin-top: 30px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex: 1 1 20%;
|
||||||
|
min-width: 150px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.3s ease;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: #0070f3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__button-container {
|
||||||
|
flex-basis: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
button {
|
||||||
|
flex-basis: 100%;
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 10px 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 100px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:first-child {
|
||||||
|
color: var(--button-primary);
|
||||||
|
border-color: var(--button-primary);
|
||||||
|
}
|
||||||
|
button:last-child {
|
||||||
|
color: var(--button-secondary);
|
||||||
|
border-color: var(--button-secondary);
|
||||||
|
margin-left: 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
payment-iq/app/features/UserRoles/EditUser/EditUser.scss
Normal file
46
payment-iq/app/features/UserRoles/EditUser/EditUser.scss
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
.edit-user {
|
||||||
|
margin-top: 30px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex: 1 1 20%;
|
||||||
|
min-width: 150px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.3s ease;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: #0070f3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__button-container {
|
||||||
|
flex-basis: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
button {
|
||||||
|
flex-basis: 100%;
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 10px 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 100px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:first-child {
|
||||||
|
color: var(--button-primary);
|
||||||
|
border-color: var(--button-primary);
|
||||||
|
}
|
||||||
|
button:last-child {
|
||||||
|
color: var(--button-secondary);
|
||||||
|
border-color: var(--button-secondary);
|
||||||
|
margin-left: 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
payment-iq/app/features/UserRoles/EditUser/EditUser.tsx
Normal file
107
payment-iq/app/features/UserRoles/EditUser/EditUser.tsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import React from "react";
|
||||||
|
import "./editUser.scss";
|
||||||
|
|
||||||
|
// Union type for form field names
|
||||||
|
export type EditUserField =
|
||||||
|
| "firstName"
|
||||||
|
| "lastName"
|
||||||
|
| "email"
|
||||||
|
| "role"
|
||||||
|
| "phone";
|
||||||
|
|
||||||
|
interface IEditUserForm {
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
email: string;
|
||||||
|
role: string;
|
||||||
|
phone: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EditUser = () => {
|
||||||
|
const [form, setForm] = React.useState<IEditUserForm>({
|
||||||
|
firstName: "",
|
||||||
|
lastName: "",
|
||||||
|
email: "",
|
||||||
|
role: "",
|
||||||
|
phone: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const name = e.target.name as EditUserField;
|
||||||
|
const value = e.target.value;
|
||||||
|
if (name === "phone") {
|
||||||
|
const filtered = value.replace(/[^0-9+\-\s()]/g, "");
|
||||||
|
setForm((prev) => ({
|
||||||
|
...prev,
|
||||||
|
phone: filtered,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
setForm((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[name]: value,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleResetForm = () => {
|
||||||
|
setForm({
|
||||||
|
firstName: "",
|
||||||
|
lastName: "",
|
||||||
|
email: "",
|
||||||
|
role: "",
|
||||||
|
phone: "",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form className="edit-user">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="First Name"
|
||||||
|
name="firstName"
|
||||||
|
value={form.firstName}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Last Name"
|
||||||
|
name="lastName"
|
||||||
|
value={form.lastName}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
placeholder="Email"
|
||||||
|
name="email"
|
||||||
|
value={form.email}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Role"
|
||||||
|
name="role"
|
||||||
|
value={form.role}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="tel"
|
||||||
|
placeholder="Phone"
|
||||||
|
name="phone"
|
||||||
|
value={form.phone}
|
||||||
|
maxLength={15}
|
||||||
|
pattern="[0-9+\-\s()]*"
|
||||||
|
onChange={handleChange}
|
||||||
|
inputMode="tel"
|
||||||
|
autoComplete="tel"
|
||||||
|
/>
|
||||||
|
<div className="edit-user__button-container">
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
<button type="button" onClick={handleResetForm}>
|
||||||
|
Clear
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditUser;
|
||||||
6
payment-iq/app/features/UserRoles/User.scss
Normal file
6
payment-iq/app/features/UserRoles/User.scss
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.edit-user {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
@ -18,6 +18,8 @@ import {
|
|||||||
AdminPanelSettings,
|
AdminPanelSettings,
|
||||||
History,
|
History,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
|
import { useState } from "react";
|
||||||
|
import EditUser from "./EditUser/EditUser";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
username: string;
|
username: string;
|
||||||
@ -40,12 +42,18 @@ export default function UserRoleCard({
|
|||||||
roles,
|
roles,
|
||||||
extraRolesCount,
|
extraRolesCount,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
|
|
||||||
|
const handleEditClick = () => {
|
||||||
|
setIsEditing(!isEditing);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card sx={{ mb: 2, minWidth: "100%" }}>
|
<Card sx={{ mb: 2, minWidth: "100%" }}>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Stack direction="row" alignItems="center" spacing={2}>
|
<Stack direction="row" alignItems="center" spacing={2}>
|
||||||
<Avatar>{username.slice(0, 2).toUpperCase()}</Avatar>
|
<Avatar>{username?.slice(0, 2).toUpperCase()}</Avatar>
|
||||||
<Box flexGrow={1}>
|
<Box flexGrow={1}>
|
||||||
<Typography fontWeight="bold">{username}</Typography>
|
<Typography fontWeight="bold">{username}</Typography>
|
||||||
<Typography variant="body2">{name}</Typography>
|
<Typography variant="body2">{name}</Typography>
|
||||||
@ -58,7 +66,7 @@ export default function UserRoleCard({
|
|||||||
<History />
|
<History />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Tooltip title="Edit">
|
<Tooltip title="Edit">
|
||||||
<IconButton>
|
<IconButton onClick={handleEditClick}>
|
||||||
<Edit />
|
<Edit />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -105,13 +113,13 @@ export default function UserRoleCard({
|
|||||||
{extraRolesCount && <Chip label={`+${extraRolesCount}`} />}
|
{extraRolesCount && <Chip label={`+${extraRolesCount}`} />}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
{isEditing && <EditUser />}
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<Box mt={2}>
|
{/* <Box mt={2}>
|
||||||
<Typography variant="caption" color="text.secondary">
|
<Typography variant="caption" color="text.secondary">
|
||||||
{lastLogin}
|
{lastLogin}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box> */}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
'use client';
|
"use client";
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export function MSWProvider({ children }: { children: React.ReactNode }) {
|
export function MSWProvider({ children }: { children: React.ReactNode }) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') {
|
if (process.env.NEXT_PUBLIC_API_MOCKING === "enabled") {
|
||||||
const { worker } = require('../../mock/browser.ts');
|
import("../../mock/browser").then(({ worker }) => {
|
||||||
worker.start();
|
// worker.start();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@ -1,39 +1,43 @@
|
|||||||
import { createTheme } from '@mui/material/styles';
|
import { createTheme } from "@mui/material/styles";
|
||||||
|
|
||||||
const palette = {
|
const palette = {
|
||||||
primary: {
|
primary: {
|
||||||
main: '#1976d2',
|
main: "#1976d2",
|
||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
main: '#d32f2f',
|
main: "#d32f2f",
|
||||||
},
|
},
|
||||||
background: {
|
background: {
|
||||||
default: '#fafafa',
|
default: "#fafafa",
|
||||||
paper: '#ffffff',
|
paper: "#ffffff",
|
||||||
primary: 'rgb(69, 190, 171)',
|
primary: "rgb(69, 190, 171)",
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
primary: '#000000',
|
primary: "#000000",
|
||||||
secondary: '#555555',
|
secondary: "#555555",
|
||||||
tertiary: '#fff',
|
tertiary: "#fff",
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
primary: "#0070f3",
|
||||||
|
secondary: "##FF00FF",
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
hover: 'rgba(0, 0, 0, 0.08)',
|
hover: "rgba(0, 0, 0, 0.08)",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const typography = {
|
const typography = {
|
||||||
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
|
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
|
||||||
h1: {
|
h1: {
|
||||||
fontSize: '3rem',
|
fontSize: "3rem",
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
},
|
},
|
||||||
h2: {
|
h2: {
|
||||||
fontSize: '2.5rem',
|
fontSize: "2.5rem",
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
},
|
},
|
||||||
body1: {
|
body1: {
|
||||||
fontSize: '1rem',
|
fontSize: "1rem",
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -41,8 +45,8 @@ const typography = {
|
|||||||
// Create the theme based on the light or dark mode preference
|
// Create the theme based on the light or dark mode preference
|
||||||
const theme = createTheme({
|
const theme = createTheme({
|
||||||
palette: {
|
palette: {
|
||||||
mode: 'light', // Change this to 'dark' for dark mode
|
mode: "light", // Change this to 'dark' for dark mode
|
||||||
...palette
|
...palette,
|
||||||
},
|
},
|
||||||
// typography,
|
// typography,
|
||||||
breakpoints: {
|
breakpoints: {
|
||||||
|
|||||||
@ -1,9 +1,4 @@
|
|||||||
// // mocks/browser.ts import { setupWorker } from "msw/browser";
|
import { setupWorker } from "msw/browser";
|
||||||
// import { handlers } from "./handlers";
|
import { handlers } from "./handlers";
|
||||||
//
|
|
||||||
// export const worker = setupWorker(...handlers);
|
|
||||||
|
|
||||||
import { setupWorker } from 'msw/browser';
|
|
||||||
import { handlers } from './handlers';
|
|
||||||
|
|
||||||
export const worker = setupWorker(...handlers);
|
export const worker = setupWorker(...handlers);
|
||||||
|
|||||||
61
payment-iq/mock/constants.ts
Normal file
61
payment-iq/mock/constants.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
export const users = [
|
||||||
|
{
|
||||||
|
merchantId: 100987998,
|
||||||
|
id: "bc6a8a55-13bc-4538-8255-cd0cec3bb4e9",
|
||||||
|
mame: "Jacob",
|
||||||
|
username: "lspaddy",
|
||||||
|
firstName: "Paddy",
|
||||||
|
lastName: "Man",
|
||||||
|
email: "patrick@omegasys.eu",
|
||||||
|
phone: "",
|
||||||
|
jobTitle: "",
|
||||||
|
enabled: true,
|
||||||
|
authorities: [
|
||||||
|
"ROLE_IIN",
|
||||||
|
"ROLE_FIRST_APPROVER",
|
||||||
|
"ROLE_RULES_ADMIN",
|
||||||
|
"ROLE_TRANSACTION_VIEWER",
|
||||||
|
"ROLE_IIN_ADMIN",
|
||||||
|
"ROLE_USER_PSP_ACCOUNT",
|
||||||
|
],
|
||||||
|
allowedMerchantIds: [100987998],
|
||||||
|
created: "2025-05-04T15:32:48.432Z",
|
||||||
|
disabledBy: null,
|
||||||
|
disabledDate: null,
|
||||||
|
disabledReason: null,
|
||||||
|
incidentNotes: false,
|
||||||
|
lastLogin: "",
|
||||||
|
lastMandatoryUpdated: "2025-05-04T15:32:48.332Z",
|
||||||
|
marketingNewsletter: false,
|
||||||
|
releaseNotes: false,
|
||||||
|
requiredActions: ["CONFIGURE_TOTP", "UPDATE_PASSWORD"],
|
||||||
|
twoFactorCondition: "required",
|
||||||
|
twoFactorCredentials: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
merchantId: 100987998,
|
||||||
|
mame: "Jacob",
|
||||||
|
id: "382eed15-1e21-41fa-b1f3-0c1adb3af714",
|
||||||
|
username: "lsterence",
|
||||||
|
firstName: "Terence",
|
||||||
|
lastName: "User",
|
||||||
|
email: "terence@omegasys.eu",
|
||||||
|
phone: "",
|
||||||
|
jobTitle: "",
|
||||||
|
enabled: true,
|
||||||
|
authorities: ["ROLE_IIN", "ROLE_FIRST_APPROVER", "ROLE_RULES_ADMIN"],
|
||||||
|
allowedMerchantIds: [100987998],
|
||||||
|
created: "2025-05-04T15:32:48.432Z",
|
||||||
|
disabledBy: null,
|
||||||
|
disabledDate: null,
|
||||||
|
disabledReason: null,
|
||||||
|
incidentNotes: false,
|
||||||
|
lastLogin: "",
|
||||||
|
lastMandatoryUpdated: "2025-05-04T15:32:48.332Z",
|
||||||
|
marketingNewsletter: false,
|
||||||
|
releaseNotes: false,
|
||||||
|
requiredActions: ["CONFIGURE_TOTP", "UPDATE_PASSWORD"],
|
||||||
|
twoFactorCondition: "required",
|
||||||
|
twoFactorCredentials: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
@ -1,72 +1,49 @@
|
|||||||
// import { http, HttpResponse } from "msw";
|
import { http, HttpResponse } from "msw";
|
||||||
//
|
|
||||||
// export const handlers = [
|
|
||||||
// http.get(
|
|
||||||
// "https://test-bo.paymentiq.io/paymentiq/backoffice/api/v2/metrics/txsummary",
|
|
||||||
// (req, _res, _ctx) => {
|
|
||||||
// const merchantId = req.url.searchParams.get("merchantId");
|
|
||||||
// const fromDate = req.url.searchParams.get("fromDate");
|
|
||||||
// const toDate = req.url.searchParams.get("toDate");
|
|
||||||
//
|
|
||||||
// console.log(merchantId, fromDate, toDate);
|
|
||||||
//
|
|
||||||
// return HttpResponse.json({
|
|
||||||
// result: {
|
|
||||||
// txCount: { total: 0, successful: 0 },
|
|
||||||
// amount: { value: "0", currency: "EUR" },
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// ),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
|
|
||||||
import { transactionDummyData } from '@/app/features/Pages/transactions/mockData';
|
|
||||||
import { http, HttpResponse } from 'msw';
|
|
||||||
|
|
||||||
export const handlers = [
|
export const handlers = [
|
||||||
// Simple GET endpoint
|
// Simple GET endpoint
|
||||||
http.get('https://api.example.com/user', () => {
|
http.get("https://api.example.com/user", () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json([
|
||||||
id: 'usr_123',
|
{
|
||||||
name: 'John Doe',
|
id: "usr_123",
|
||||||
email: 'john@example.com'
|
name: "John Doe",
|
||||||
});
|
email: "john@example.com",
|
||||||
|
},
|
||||||
|
]);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// POST endpoint with request validation
|
// POST endpoint with request validation
|
||||||
http.post('https://api.example.com/login', async ({ request }) => {
|
http.post("https://api.example.com/login", async ({ request }) => {
|
||||||
const { username, password } = await request.json() as { username: string; password: string };
|
const { username, password } = (await request.json()) as {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
|
||||||
if (username === 'admin' && password === 'password123') {
|
if (username === "admin" && password === "password123") {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
token: 'mock-jwt-token',
|
token: "mock-jwt-token",
|
||||||
user: { id: 'usr_123', name: 'Admin User' }
|
user: { id: "usr_123", name: "Admin User" },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return HttpResponse.json(
|
return HttpResponse.json({ error: "Invalid credentials" }, { status: 401 });
|
||||||
{ error: 'Invalid credentials' },
|
|
||||||
{ status: 401 }
|
|
||||||
);
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
||||||
// Example with query parameters
|
// Example with query parameters
|
||||||
http.get('https://api.example.com/products', ({ request }) => {
|
http.get("https://api.example.com/products", ({ request }) => {
|
||||||
// Parse the URL to access query parameters
|
// Parse the URL to access query parameters
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
|
|
||||||
// Get query parameters
|
// Get query parameters
|
||||||
const category = url.searchParams.get('category');
|
const category = url.searchParams.get("category");
|
||||||
const sort = url.searchParams.get('sort') || 'price';
|
const sort = url.searchParams.get("sort") || "price";
|
||||||
const page = url.searchParams.get('page') || '1';
|
const page = url.searchParams.get("page") || "1";
|
||||||
const limit = url.searchParams.get('limit') || '10';
|
const limit = url.searchParams.get("limit") || "10";
|
||||||
|
|
||||||
// Validate parameters
|
// Validate parameters
|
||||||
if (limit && parseInt(limit) > 100) {
|
if (limit && parseInt(limit) > 100) {
|
||||||
return HttpResponse.json(
|
return HttpResponse.json(
|
||||||
{ error: 'Limit cannot exceed 100' },
|
{ error: "Limit cannot exceed 100" },
|
||||||
{ status: 400 }
|
{ status: 400 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -74,15 +51,15 @@ export const handlers = [
|
|||||||
// Generate mock response based on parameters
|
// Generate mock response based on parameters
|
||||||
const mockProducts = Array.from({ length: parseInt(limit) }, (_, i) => ({
|
const mockProducts = Array.from({ length: parseInt(limit) }, (_, i) => ({
|
||||||
id: i + 1,
|
id: i + 1,
|
||||||
name: `Product ${i + 1}${category ? ` in ${category}` : ''}`,
|
name: `Product ${i + 1}${category ? ` in ${category}` : ""}`,
|
||||||
price: Math.floor(Math.random() * 100),
|
price: Math.floor(Math.random() * 100),
|
||||||
category: category || 'general',
|
category: category || "general",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Sort products if sort parameter provided
|
// Sort products if sort parameter provided
|
||||||
if (sort === 'price') {
|
if (sort === "price") {
|
||||||
mockProducts.sort((a, b) => a.price - b.price);
|
mockProducts.sort((a, b) => a.price - b.price);
|
||||||
} else if (sort === 'name') {
|
} else if (sort === "name") {
|
||||||
mockProducts.sort((a, b) => a.name.localeCompare(b.name));
|
mockProducts.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,38 +71,38 @@ export const handlers = [
|
|||||||
sortBy: sort,
|
sortBy: sort,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
http.get('https://api.example.com/transactions', ({ request }) => {
|
http.get("https://api.example.com/transactions", ({ request }) => {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
|
|
||||||
// Get query parameters
|
// Get query parameters
|
||||||
const userId = url.searchParams.get('userId');
|
const userId = url.searchParams.get("userId");
|
||||||
const state = url.searchParams.get('state');
|
const state = url.searchParams.get("state");
|
||||||
const statusCode = url.searchParams.get('statusCode');
|
const statusCode = url.searchParams.get("statusCode");
|
||||||
|
|
||||||
// Filter transactions based on query parameters
|
// Filter transactions based on query parameters
|
||||||
let filteredTransactions = [...transactionDummyData];
|
let filteredTransactions = [...transactionDummyData];
|
||||||
|
|
||||||
if (userId) {
|
if (userId) {
|
||||||
filteredTransactions = filteredTransactions.filter(
|
filteredTransactions = filteredTransactions.filter(
|
||||||
tx => tx.user.toString() === userId
|
(tx) => tx.user.toString() === userId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
filteredTransactions = filteredTransactions.filter(
|
filteredTransactions = filteredTransactions.filter(
|
||||||
tx => tx.state.toLowerCase() === state.toLowerCase()
|
(tx) => tx.state.toLowerCase() === state.toLowerCase()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statusCode) {
|
if (statusCode) {
|
||||||
filteredTransactions = filteredTransactions.filter(
|
filteredTransactions = filteredTransactions.filter(
|
||||||
tx => tx.pspStatusCode.toString() === statusCode
|
(tx) => tx.pspStatusCode.toString() === statusCode
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
transactions: filteredTransactions,
|
transactions: filteredTransactions,
|
||||||
count: filteredTransactions.length
|
count: filteredTransactions.length,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import type { NextConfig } from "next";
|
|||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
/* config options here */
|
/* config options here */
|
||||||
webpack: (config) => {
|
webpack: (config) => {
|
||||||
if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') {
|
if (process.env.NEXT_PUBLIC_API_MOCKING === "enabled") {
|
||||||
config.resolve.alias['@mswjs/interceptors'] = false;
|
config.resolve.alias["@mswjs/interceptors"] = false;
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -11,6 +11,8 @@
|
|||||||
--text-tertiary: #{$text-tertiary};
|
--text-tertiary: #{$text-tertiary};
|
||||||
--hover-color: #{$hover-color};
|
--hover-color: #{$hover-color};
|
||||||
--font-family-base: #{$font-family-base};
|
--font-family-base: #{$font-family-base};
|
||||||
|
--button-primary: #{$button-primary};
|
||||||
|
--button-secondary: #{$button-secondary};
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
|
|||||||
@ -5,6 +5,8 @@ $background-primary: rgb(69, 190, 171);
|
|||||||
$text-primary: #000000;
|
$text-primary: #000000;
|
||||||
$text-secondary: #555555;
|
$text-secondary: #555555;
|
||||||
$text-tertiary: #ffffff;
|
$text-tertiary: #ffffff;
|
||||||
|
$button-primary: #0070f3;
|
||||||
|
$button-secondary: #ff00ff;
|
||||||
$hover-color: rgba(0, 0, 0, 0.08);
|
$hover-color: rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
$font-family-base: "Roboto", "Helvetica", "Arial", sans-serif;
|
$font-family-base: "Roboto", "Helvetica", "Arial", sans-serif;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user