Skip to content

Commit

Permalink
Dashboard improvement (#2207)
Browse files Browse the repository at this point in the history
After clicking the FETCH button, if the data is fetched successfully
then a new button labelled as 'MORE' appears, clicking on this opens a
dropdown menu which has 3 options: Disable2fa, Disable Passkeys and
Close Family, clicking on any of the option directly performs the action
required.
  • Loading branch information
ua741 authored Jun 19, 2024
2 parents cca1b19 + b7d3e54 commit 431ad66
Show file tree
Hide file tree
Showing 9 changed files with 5,793 additions and 557 deletions.
5,047 changes: 5,047 additions & 0 deletions infra/staff/package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion infra/staff/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"dependencies": {
"react": "^18",
"react-dom": "^18",
"react-toastify": "^10.0.5",
"zod": "^3"
},
"devDependencies": {
Expand All @@ -28,7 +29,7 @@
"prettier": "^3",
"prettier-plugin-organize-imports": "^3.2",
"prettier-plugin-packagejson": "^2.5",
"typescript": "^5",
"typescript": "^5.4.5",
"vite": "^5.2"
},
"packageManager": "[email protected]"
Expand Down
124 changes: 124 additions & 0 deletions infra/staff/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
.fetch-button-container {
margin-right: 180px;
margin-left: 10px;
}

.content-wrapper {
display: flex;
align-items: flex-start;
margin-left: 175px;
}

.fetch-button-container button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
background-color: #009879;
color: white;
border: none;
border-radius: 5px;
margin-top: 20px;
}

.fetch-button-container button:hover {
background-color: #007c6c;
}

.sidebar {
padding: 20px;
flex: 0 0 auto;
}

.button-container {
display: flex;
gap: 10px;
}

button {
padding: 10px 20px;
font-size: 16px;
}

.error-message {
margin-top: 20px;
color: red;
}

.message {
position: fixed;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
padding: 10px;
border-radius: 5px;
background-color: #f0f0f0;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}

.message.error {
background-color: #f44336;
color: white;
}

.message.success {
background-color: #4caf50;
color: white;
}

.dropdown-container {
margin-bottom: 20px;
position: relative; /* Ensure relative positioning for dropdown menu */
}

.more-button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
background-color: #009879;
color: white;
border: none;
border-radius: 5px;
margin-top: 1px;
}

.more-button:hover {
background-color: #007c6c;
}

.dropdown-menu {
position: absolute;
top: calc(100% + 5px); /* Position right below the More button */
left: 0;
z-index: 100;
display: block;
background-color: #fff;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border: 1px solid #ccc;
border-radius: 5px;
padding: 10px;
max-height: 150px; /* Example: Set max height for scrollability */
overflow-y: auto; /* Enable vertical scroll */
}

/* Remove bullets from unordered list */
.dropdown-menu ul {
list-style-type: none;
padding: 0;
margin: 0;
}

.dropdown-menu button {
display: block;
width: 100%;
padding: 8px 16px;
font-size: 14px;
color: #333;
background-color: transparent;
border: none;
cursor: pointer;
transition: background-color 0.3s ease;
}

.dropdown-menu button:hover {
background-color: #f0f0f0;
}
97 changes: 66 additions & 31 deletions infra/staff/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import React, { useEffect, useState } from "react";
import "./App.css";
import { Sidebar } from "./components/Sidebar";
import { apiOrigin } from "./services/support";
import S from "./utils/strings";

type User = Record<
string,
string | number | boolean | null | undefined | Record<string, unknown>
>;
type UserData = Record<string, User>;

export const App: React.FC = () => {
const [token, setToken] = useState("");
const [email, setEmail] = useState("");
const [userData, setUserData] = useState<any>(null);
const [token, setToken] = useState<string>("");
const [email, setEmail] = useState<string>("");
const [userData, setUserData] = useState<UserData | null>(null);
const [error, setError] = useState<string | null>(null);
const [isDataFetched, setIsDataFetched] = useState<boolean>(false); // Track if data has been fetched successfully

useEffect(() => {
const storedToken = localStorage.getItem("token");
Expand All @@ -25,25 +34,32 @@ export const App: React.FC = () => {

const fetchData = async () => {
try {
const url = `${apiOrigin}/admin/user?email=${email}&token=${token}`;
const encodedEmail = encodeURIComponent(email);
const encodedToken = encodeURIComponent(token);
const url = `${apiOrigin}/admin/user?email=${encodedEmail}&token=${encodedToken}`;
console.log(`Fetching data from URL: ${url}`);
const response = await fetch(url);
if (!response.ok) {
throw new Error("Network response was not ok");
}
const userData = await response.json();
console.log("API Response:", userData);
setUserData(userData);
const userDataResponse = (await response.json()) as UserData;
console.log("API Response:", userDataResponse);
setUserData(userDataResponse);
setError(null);
setIsDataFetched(true); // Set to true when data is successfully fetched
} catch (error) {
console.error("Error fetching data:", error);
setError((error as Error).message);
setIsDataFetched(false); // Set to false if there's an error fetching data
}
};

const renderAttributes = (data: any) => {
const renderAttributes = (
data: Record<string, unknown> | User | null,
): React.ReactNode => {
if (!data) return null;

let nullAttributes: string[] = [];
const nullAttributes: string[] = [];

const rows = Object.entries(data).map(([key, value]) => {
console.log("Processing key:", key, "value:", value);
Expand All @@ -67,7 +83,9 @@ export const App: React.FC = () => {
{key.toUpperCase()}
</td>
</tr>
{renderAttributes(value)}
{renderAttributes(
value as Record<string, unknown> | User,
)}
</React.Fragment>
);
} else {
Expand All @@ -87,17 +105,26 @@ export const App: React.FC = () => {
displayValue = `${(value / 1024 ** 3).toFixed(2)} GB`;
} else if (typeof value === "string") {
try {
const parsedValue = JSON.parse(value);
const parsedValue = JSON.parse(
value,
) as React.ReactNode;
displayValue = parsedValue;
} catch (error) {
displayValue = value;
}
} else if (typeof value === "object" && value !== null) {
displayValue = JSON.stringify(value, null, 2); // Pretty print JSON
} else if (value === null) {
displayValue = "null";
} else if (typeof value !== "undefined") {
} else if (
typeof value === "boolean" ||
typeof value === "number"
) {
displayValue = value.toString();
} else {
} else if (typeof value === "undefined") {
displayValue = "undefined";
} else {
displayValue = value as string; // Fallback for any other types
}

return (
Expand Down Expand Up @@ -128,11 +155,19 @@ export const App: React.FC = () => {
return rows;
};

const handleKeyPress = (event: React.KeyboardEvent<HTMLFormElement>) => {
if (event.key === "Enter") {
event.preventDefault(); // Prevent form submission
fetchData().catch((error: unknown) =>
console.error("Fetch data error:", error),
);
}
};

return (
<div className="container center-table">
<h1>{S.hello}</h1>

<form className="input-form">
<form className="input-form" onKeyPress={handleKeyPress}>
<div className="input-group">
<label>
Token:
Expand Down Expand Up @@ -164,21 +199,19 @@ export const App: React.FC = () => {
</label>
</div>
</form>
<div className="fetch-button">
<button
onClick={fetchData}
style={{
padding: "10px 20px",
fontSize: "16px",
cursor: "pointer",
backgroundColor: "#009879",
color: "white",
border: "none",
borderRadius: "5px",
}}
>
FETCH
</button>
<div className="content-wrapper">
{isDataFetched && <Sidebar token={token} email={email} />}
<div className="fetch-button-container">
<button
onClick={() => {
fetchData().catch((error: unknown) =>
console.error("Fetch data error:", error),
);
}}
>
FETCH
</button>
</div>
</div>
<br />
{error && <p style={{ color: "red" }}>{`Error: ${error}`}</p>}
Expand Down Expand Up @@ -208,7 +241,7 @@ export const App: React.FC = () => {
{category.toUpperCase()}
</td>
</tr>
{renderAttributes(userData[category])}
{renderAttributes(userData[category] ?? null)}
</React.Fragment>
))}
</tbody>
Expand All @@ -222,3 +255,5 @@ export const App: React.FC = () => {
</div>
);
};

export default App;
Loading

0 comments on commit 431ad66

Please sign in to comment.