Skip to content

Commit 4ebc7ef

Browse files
committed
feat: add AccountDialog component with user profile display
- Introduced AccountDialog component for displaying user account information. - Implemented loading and error states for user profile data retrieval. - Added styles in AccountDialog.scss for layout and visual presentation of the dialog. - Integrated Gravatar for user avatars based on email.
1 parent d2044e0 commit 4ebc7ef

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
.account-dialog {
2+
3+
&__wrapper {
4+
position: absolute;
5+
top: 0;
6+
left: 0;
7+
right: 0;
8+
bottom: 0;
9+
z-index: 1000;
10+
background-color: rgba(0, 0, 0, 0.2);
11+
backdrop-filter: blur(1px);
12+
}
13+
14+
&__title-container {
15+
display: flex;
16+
align-items: center;
17+
justify-content: space-between;
18+
}
19+
20+
&__title {
21+
margin: 0;
22+
font-size: 1.2rem;
23+
font-weight: 600;
24+
}
25+
26+
&__content {
27+
padding: 1rem;
28+
min-height: 200px;
29+
display: flex;
30+
flex-direction: column;
31+
}
32+
33+
&__loading, &__error {
34+
display: flex;
35+
align-items: center;
36+
justify-content: center;
37+
min-height: 200px;
38+
font-size: 1rem;
39+
color: var(--text-primary-color);
40+
}
41+
42+
&__error {
43+
color: #e74c3c;
44+
}
45+
46+
&__profile {
47+
display: flex;
48+
align-items: flex-start;
49+
padding: 1.25rem;
50+
border-radius: 8px;
51+
background-color: var(--dialog-bg-color);
52+
}
53+
54+
&__avatar {
55+
margin-right: 1.25rem;
56+
}
57+
58+
&__gravatar {
59+
width: 90px;
60+
height: 90px;
61+
border-radius: 50%;
62+
object-fit: cover;
63+
border: 2px solid var(--text-primary-color);
64+
}
65+
66+
&__user-info {
67+
flex: 1;
68+
}
69+
70+
&__name {
71+
margin: 0 0 0 0;
72+
font-size: 1.3rem;
73+
font-weight: 600;
74+
color: var(--text-primary-color);
75+
display: flex;
76+
align-items: center;
77+
flex-wrap: wrap;
78+
gap: 0.5rem;
79+
}
80+
81+
&__username {
82+
margin: 0 0 1.5rem 0;
83+
font-size: 0.95rem;
84+
color: var(--text-secondary-color);
85+
}
86+
87+
&__user-id {
88+
margin: 0;
89+
font-size: 0.75rem;
90+
font-family: monospace;
91+
color: var(--text-secondary-color);
92+
opacity: 0.7;
93+
}
94+
95+
&__verified {
96+
font-size: 0.75rem;
97+
color: #2ecc71;
98+
background-color: rgba(46, 204, 113, 0.1);
99+
padding: 0.15rem 0.4rem;
100+
border-radius: 4px;
101+
display: inline-flex;
102+
align-items: center;
103+
vertical-align: middle;
104+
}
105+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import React, { useState, useCallback } from "react";
2+
import { Dialog } from "@atyrode/excalidraw";
3+
import { useUserProfile } from "../api/hooks";
4+
import md5 from 'crypto-js/md5';
5+
import "./AccountDialog.scss";
6+
7+
interface AccountDialogProps {
8+
excalidrawAPI?: any;
9+
onClose?: () => void;
10+
}
11+
12+
// Function to generate gravatar URL
13+
const getGravatarUrl = (email: string, size = 100) => {
14+
const hash = md5(email.toLowerCase().trim()).toString();
15+
return `https://www.gravatar.com/avatar/${hash}?s=${size}&d=identicon`;
16+
};
17+
18+
const AccountDialog: React.FC<AccountDialogProps> = ({
19+
excalidrawAPI,
20+
onClose,
21+
}) => {
22+
const [modalIsShown, setModalIsShown] = useState(true);
23+
const { data: profile, isLoading, isError } = useUserProfile();
24+
25+
const handleClose = useCallback(() => {
26+
setModalIsShown(false);
27+
if (onClose) {
28+
onClose();
29+
}
30+
}, [onClose]);
31+
32+
// Dialog content with user profile information
33+
const dialogContent = (
34+
<div className="account-dialog__content">
35+
{isLoading && (
36+
<div className="account-dialog__loading">
37+
Loading account information...
38+
</div>
39+
)}
40+
41+
{isError && (
42+
<div className="account-dialog__error">
43+
Error loading account information. Please try again later.
44+
</div>
45+
)}
46+
47+
{profile && !isLoading && !isError && (
48+
<div className="account-dialog__profile">
49+
<div className="account-dialog__avatar">
50+
<img
51+
src={getGravatarUrl(profile.email)}
52+
alt={profile.username}
53+
className="account-dialog__gravatar"
54+
/>
55+
</div>
56+
<div className="account-dialog__user-info">
57+
<h2 className="account-dialog__name">
58+
{profile.name || profile.username}
59+
{profile.email_verified && (
60+
<span className="account-dialog__verified">✓ Verified</span>
61+
)}
62+
</h2>
63+
<p className="account-dialog__username">{profile.username}</p>
64+
<p className="account-dialog__user-id">{profile.id}</p>
65+
</div>
66+
</div>
67+
)}
68+
</div>
69+
);
70+
71+
return (
72+
<>
73+
{modalIsShown && (
74+
<div className="account-dialog__wrapper">
75+
<Dialog
76+
className="account-dialog"
77+
size="small"
78+
onCloseRequest={handleClose}
79+
title={
80+
<div className="account-dialog__title-container">
81+
<h2 className="account-dialog__title">Account</h2>
82+
</div>
83+
}
84+
closeOnClickOutside={true}
85+
children={dialogContent}
86+
/>
87+
</div>
88+
)}
89+
</>
90+
);
91+
};
92+
93+
export default AccountDialog;

0 commit comments

Comments
 (0)