Skip to content

Commit 5b3efba

Browse files
authored
Merge branch 'main' into ahmad/account_management_dashboard
2 parents 3eb6d83 + a12fae5 commit 5b3efba

File tree

21 files changed

+1139
-1
lines changed

21 files changed

+1139
-1
lines changed

.github/workflows/deploy.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ jobs:
3838
account_management_dashboard)
3939
echo "EXTRA_ARGS=" >> $GITHUB_ENV
4040
;;
41+
admin_dashboard)
42+
echo "EXTRA_ARGS=" >> $GITHUB_ENV
43+
;;
4144
stock_market_dashboard)
4245
echo "EXTRA_ARGS=" >> $GITHUB_ENV
4346
;;

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
.web
66
__pycache__/
77
venv/
8-
*/.DS_Store
8+
*/.DS_Store
9+
.idea

admin_dashboard/.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.states
2+
assets/external/
3+
*.db
4+
*.py[cod]
5+
.venv/
6+
venv/
7+
.vscode/
8+
.web
9+
__pycache__/
10+
.DS_Store
11+
.idea/

admin_dashboard/admin_dashboard/__init__.py

Whitespace-only changes.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import reflex as rx
2+
import reflex.components.radix.themes as rdxt
3+
4+
from admin_dashboard.components.customer_details import customer_details
5+
from admin_dashboard.components.data_table import data_table
6+
from admin_dashboard.components.navigation import navigation
7+
8+
9+
def index() -> rx.Component:
10+
"""The main page layout for the dashboard."""
11+
return rdxt.theme(
12+
rx.el.div(
13+
navigation(),
14+
rx.el.div(
15+
rx.el.div(
16+
data_table(),
17+
class_name="flex-grow p-6 overflow-y-auto",
18+
),
19+
customer_details(),
20+
class_name="flex flex-row h-[calc(100vh-56px)] overflow-hidden",
21+
),
22+
class_name="bg-gray-100 h-screen overflow-hidden",
23+
),
24+
appearance="light",
25+
)
26+
27+
28+
def mock_page(title: str) -> rx.Component:
29+
"""Creates a simple mock page layout."""
30+
return rdxt.theme(
31+
rx.el.div(
32+
navigation(),
33+
rx.el.div(
34+
rx.el.h1(
35+
title,
36+
class_name="text-2xl font-bold mb-4 text-gray-800",
37+
),
38+
rx.el.p(
39+
f"Content for {title} goes here.",
40+
class_name="text-gray-600",
41+
),
42+
class_name="p-6",
43+
),
44+
class_name="bg-gray-100 h-screen",
45+
),
46+
appearance="light",
47+
)
48+
49+
50+
def sales_pipeline_page() -> rx.Component:
51+
"""Mock Sales Pipeline page."""
52+
return mock_page("Sales Pipeline")
53+
54+
55+
def hr_portal_page() -> rx.Component:
56+
"""Mock HR Portal page."""
57+
return mock_page("HR Portal")
58+
59+
60+
def customer_success_hub_page() -> rx.Component:
61+
"""Mock Customer Success Hub page."""
62+
return mock_page("Customer Success Hub")
63+
64+
65+
app = rx.App(theme=rx.theme(appearance="light"), stylesheets=[])
66+
app.add_page(index, route="/")
67+
app.add_page(sales_pipeline_page, route="/sales-pipeline")
68+
app.add_page(hr_portal_page, route="/hr-portal")
69+
app.add_page(customer_success_hub_page, route="/customer-success-hub")

admin_dashboard/admin_dashboard/components/__init__.py

Whitespace-only changes.
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import reflex as rx
2+
import reflex.components.recharts as recharts
3+
4+
from admin_dashboard.states.dashboard_state import (
5+
CustomerData,
6+
DashboardState,
7+
)
8+
9+
10+
def detail_item(label: str, value: rx.Var[str]) -> rx.Component:
11+
"""Displays a single detail item with label and value."""
12+
return rx.el.div(
13+
rx.el.dt(
14+
label,
15+
class_name="text-sm font-medium text-gray-500",
16+
),
17+
rx.el.dd(value, class_name="mt-1 text-sm text-gray-900"),
18+
class_name="py-2",
19+
)
20+
21+
22+
def license_stat(label: str, value: rx.Var[int], change: rx.Var[int]) -> rx.Component:
23+
"""Displays a license statistic card."""
24+
return rx.el.div(
25+
rx.el.p(
26+
label,
27+
class_name="text-sm font-medium text-gray-500",
28+
),
29+
rx.el.div(
30+
rx.el.span(
31+
value,
32+
class_name="text-3xl font-bold text-gray-900 mr-2",
33+
),
34+
rx.el.span(
35+
rx.icon(
36+
rx.cond(change > 0, "arrow-up", "arrow-down"),
37+
size=16,
38+
class_name="mr-1",
39+
),
40+
rx.cond(change < 0, change * -1, change),
41+
"%",
42+
class_name=rx.cond(
43+
change > 0,
44+
"text-sm font-medium text-green-600 bg-green-100 px-2 py-0.5 rounded-full inline-flex items-center",
45+
"text-sm font-medium text-red-600 bg-red-100 px-2 py-0.5 rounded-full inline-flex items-center",
46+
),
47+
),
48+
class_name="flex items-baseline",
49+
),
50+
class_name="p-4 bg-white rounded-lg border border-gray-200 shadow-sm",
51+
)
52+
53+
54+
def customer_details_panel(
55+
customer: CustomerData,
56+
) -> rx.Component:
57+
"""Panel showing detailed information about a selected customer."""
58+
usage_percentage = rx.cond(
59+
customer["licenses"] > 0,
60+
round(customer["active_licenses"] * 100 / customer["licenses"]).to(int),
61+
0,
62+
)
63+
return rx.el.div(
64+
rx.el.h3(
65+
customer["customer_name"],
66+
class_name="text-xl font-semibold text-gray-900 mb-4",
67+
),
68+
rx.el.div(
69+
rx.el.h4(
70+
"Usage",
71+
class_name="text-md font-medium text-gray-700 mb-2",
72+
),
73+
rx.el.div(
74+
rx.el.p(
75+
usage_percentage.to_string() + "%",
76+
class_name="text-5xl font-bold text-emerald-600 text-center",
77+
),
78+
class_name="flex items-center justify-center w-32 h-32 rounded-full bg-emerald-50 border-4 border-emerald-200 mx-auto mb-4",
79+
),
80+
class_name="mb-6 p-4 bg-white rounded-lg border border-gray-200 shadow-sm",
81+
),
82+
rx.el.div(
83+
rx.el.h4(
84+
"Details",
85+
class_name="text-md font-medium text-gray-700 mb-2",
86+
),
87+
rx.el.dl(
88+
detail_item(
89+
"Revenue",
90+
"$" + customer["revenue"].to_string(),
91+
),
92+
detail_item("Platform Type", customer["platform"]),
93+
detail_item("Industry", customer["industry"]),
94+
),
95+
class_name="mb-6 p-4 bg-white rounded-lg border border-gray-200 divide-y divide-gray-200 shadow-sm",
96+
),
97+
rx.el.div(
98+
rx.el.h4(
99+
"License Utilization",
100+
class_name="text-md font-medium text-gray-700 mb-3",
101+
),
102+
rx.el.div(
103+
license_stat(
104+
"Active Licenses",
105+
customer["active_licenses"],
106+
customer["active_license_growth"],
107+
),
108+
license_stat(
109+
"Total Licenses",
110+
customer["licenses"],
111+
customer["license_growth"],
112+
),
113+
class_name="grid grid-cols-2 gap-4 mb-4",
114+
),
115+
class_name="mb-6",
116+
),
117+
rx.el.div(
118+
rx.el.h4(
119+
"Usage Over Time",
120+
class_name="text-md font-medium text-gray-700 mb-2",
121+
),
122+
rx.el.div(
123+
recharts.line_chart(
124+
recharts.cartesian_grid(
125+
horizontal=True,
126+
vertical=False,
127+
class_name="opacity-25 stroke-gray-300",
128+
),
129+
recharts.line(
130+
data_key="usage",
131+
stroke="#10B981",
132+
stroke_width=2,
133+
dot=False,
134+
type_="natural",
135+
),
136+
recharts.x_axis(
137+
data_key="month",
138+
axis_line=False,
139+
tick_size=10,
140+
tick_line=False,
141+
interval="preserveStartEnd",
142+
),
143+
recharts.y_axis(
144+
axis_line=False,
145+
tick_size=0,
146+
tick_line=False,
147+
width=30,
148+
),
149+
data=customer["usage_history"],
150+
height=250,
151+
margin={
152+
"top": 5,
153+
"right": 10,
154+
"left": 0,
155+
"bottom": 5,
156+
},
157+
),
158+
class_name="p-2 bg-white rounded-lg border border-gray-200 flex items-center justify-center shadow-sm",
159+
),
160+
),
161+
class_name="px-5 pt-5 pb-14 bg-gray-50 rounded-lg shadow-inner h-[100vh] overflow-y-auto",
162+
)
163+
164+
165+
def customer_details() -> rx.Component:
166+
"""Component to display details of the selected customer or a placeholder."""
167+
return rx.el.div(
168+
rx.cond(
169+
DashboardState.selected_customer,
170+
customer_details_panel(DashboardState.selected_customer),
171+
rx.el.div(
172+
rx.el.p(
173+
"Select a customer to see details.",
174+
class_name="text-center text-gray-500 text-lg",
175+
),
176+
class_name="flex items-center justify-center h-[100vh] p-5 bg-gray-50 rounded-lg shadow-inner",
177+
),
178+
),
179+
class_name="w-1/3 flex-shrink-0 h-[100vh] overflow-hidden sticky top-0 right-0 border-l border-gray-200",
180+
)

0 commit comments

Comments
 (0)