Skip to content

Commit 07467ac

Browse files
authored
Merge pull request #2448 from airqo-platform/staging
move to production
2 parents 94d2152 + 1ed61a3 commit 07467ac

File tree

9 files changed

+41
-120
lines changed

9 files changed

+41
-120
lines changed

netmanager-app/app/types/users.ts

+3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export interface UserDetails {
6161
rateLimit: number | null;
6262
jobTitle?: string | null;
6363
description?: string | null;
64+
timezone?: string | null;
6465
profilePicture: string | null;
6566
phoneNumber: string | null;
6667
updatedAt: string;
@@ -105,6 +106,8 @@ export interface DecodedToken {
105106
privilege: string;
106107
country: string | null;
107108
profilePicture: string | null;
109+
description: string | null;
110+
timezone: string | null;
108111
phoneNumber: string | null;
109112
createdAt: string;
110113
updatedAt: string;

netmanager-app/components/Settings/ApiTokens.tsx

+14-68
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type React from "react"
2-
import { useEffect, useState } from "react"
2+
import { useState } from "react"
33
import moment from "moment"
4-
import { useAppDispatch, useAppSelector } from "@/core/redux/hooks"
4+
import { useAppDispatch } from "@/core/redux/hooks"
55
import { useToast } from "@/components/ui/use-toast"
66
import { Button } from "@/components/ui/button"
77
import { performRefresh } from "@/core/redux/slices/clientsSlice"
@@ -11,99 +11,51 @@ import DialogWrapper from "./DialogWrapper"
1111
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
1212
import { Skeleton } from "@/components/ui/skeleton"
1313
import { Edit, Copy, Info, Plus } from "lucide-react"
14-
import { users } from "@/core/apis/users"
1514
import type { Client } from "@/app/types/clients"
1615
import { settings } from "@/core/apis/settings"
16+
import { useUserClients } from "@/core/hooks/useUserClients"
1717

1818

1919
const UserClientsTable = () => {
2020
const dispatch = useAppDispatch()
2121
const { toast } = useToast()
2222
const [showInfoModal, setShowInfoModal] = useState(false)
23-
const [isLoading, setIsLoading] = useState(false)
2423
const [isLoadingToken, setIsLoadingToken] = useState(false)
2524
const [isLoadingActivationRequest, setIsLoadingActivationRequest] = useState(false)
2625
const [openEditForm, setOpenEditForm] = useState(false)
2726
const [openCreateForm, setOpenCreateForm] = useState(false)
2827
const [selectedClient, setSelectedClient] = useState({} as Client)
29-
const userInfo = useAppSelector((state) => state.user.userDetails)
30-
const [clients, setClients] = useState<Client[]>([])
31-
const [clientsDetails, setClientsDetails] = useState<Client[]>([])
32-
const [currentPage, setCurrentPage] = useState(1)
33-
const itemsPerPage = 4
28+
const { clients, isLoading, error } = useUserClients();
29+
console.log(clients)
3430

35-
const fetchClients = async () => {
36-
setIsLoading(true)
37-
try {
38-
const res = await users.getUserDetails(userInfo?._id || "")
39-
if (res) {
40-
dispatch({ type: "ADD_CLIENTS", payload: res.users[0].clients })
41-
setCurrentPage(1)
42-
}
43-
setClients(res.users[0].clients)
44-
} catch (error) {
45-
toast({
46-
title: "Error",
47-
description: "Failed to fetch user details",
48-
variant: "destructive",
49-
})
50-
} finally {
51-
setIsLoading(false)
52-
}
53-
}
54-
55-
const fetchClientDetails = async () => {
56-
setIsLoading(true)
57-
try {
58-
const response = await settings.getUserClientsApi(userInfo?._id || "")
59-
if (response) {
60-
dispatch({ type: "ADD_CLIENTS_DETAILS", payload: response })
61-
}
62-
setClientsDetails(response.clients)
63-
} catch (error) {
64-
console.error(error)
65-
toast({
66-
title: "Error",
67-
description: "Failed to fetch client details",
68-
variant: "destructive",
69-
})
70-
} finally {
71-
setIsLoading(false)
72-
}
73-
}
74-
75-
useEffect(() => {
76-
fetchClients()
77-
fetchClientDetails()
78-
}, [userInfo?._id, dispatch])
7931

8032
const hasAccessToken = (clientId: string): boolean => {
8133
const client =
82-
Array.isArray(clientsDetails) && clientsDetails
83-
? clientsDetails?.find((client: Client) => client._id === clientId)
34+
Array.isArray(clients) && clients
35+
? clients?.find((client: Client) => client._id === clientId)
8436
: undefined
8537
return client?.access_token?.token ? true : false
8638
}
8739

8840
const getClientToken = (clientID: string) => {
8941
const client =
90-
Array.isArray(clientsDetails) && clientsDetails
91-
? clientsDetails?.find((client: Client) => client._id === clientID)
42+
Array.isArray(clients) && clients
43+
? clients?.find((client: Client) => client._id === clientID)
9244
: undefined
9345
return client && client.access_token && client.access_token.token
9446
}
9547
const getClientTokenExpiryDate = (clientID: string) => {
9648
const client =
97-
Array.isArray(clientsDetails) && clientsDetails
98-
? clientsDetails?.find((client: Client) => client._id === clientID)
49+
Array.isArray(clients) && clients
50+
? clients?.find((client: Client) => client._id === clientID)
9951
: undefined
10052
return client && client.access_token && client.access_token.expires
10153
}
10254

10355
const getClientTokenCreateAt = (clientID: string) => {
10456
const client =
105-
Array.isArray(clientsDetails) && clientsDetails
106-
? clientsDetails?.find((client: Client) => client._id === clientID)
57+
Array.isArray(clients) && clients
58+
? clients?.find((client: Client) => client._id === clientID)
10759
: undefined
10860
return client && client.access_token && client.access_token.createdAt
10961
}
@@ -117,6 +69,7 @@ const UserClientsTable = () => {
11769
} else {
11870
try {
11971
const response = await settings.generateTokenApi(res)
72+
await queryClient.invalidateQueries({ queryKey: ["clients"] });
12073
if (response) {
12174
toast({
12275
title: "Success",
@@ -168,10 +121,6 @@ const UserClientsTable = () => {
168121
return Array.isArray(client.ip_addresses) ? client.ip_addresses.join(", ") : client.ip_addresses
169122
}
170123

171-
const handleClientCreated = () => {
172-
fetchClients()
173-
fetchClientDetails()
174-
}
175124

176125
return (
177126
<div className="overflow-x-auto">
@@ -202,7 +151,6 @@ const UserClientsTable = () => {
202151
</TableRow>
203152
) : clients?.length > 0 ? (
204153
clients
205-
.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage)
206154
.map((client: Client, index: number) => (
207155
<TableRow key={index}>
208156
<TableCell className="font-medium">{client?.name}</TableCell>
@@ -292,12 +240,10 @@ const UserClientsTable = () => {
292240
open={openEditForm}
293241
onClose={() => setOpenEditForm(false)}
294242
data={selectedClient}
295-
onClientUpdated={handleClientCreated}
296243
/>
297244
<CreateClientForm
298245
open={openCreateForm}
299246
onClose={() => setOpenCreateForm(false)}
300-
onClientCreated={handleClientCreated}
301247
/>
302248
<DialogWrapper
303249
open={showInfoModal}

netmanager-app/components/Settings/Clients.tsx

+11-30
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ import {
1515
ActivateClientDialog,
1616
DeactivateClientDialog,
1717
} from "@/components/clients/dialogs";
18-
import { getClientsApi } from "@/core/apis/analytics";
1918
import { settings } from "@/core/apis/settings";
2019
import { useToast } from "@/components/ui/use-toast";
2120
import type { Client } from "@/app/types/clients";
2221
import { Search, ArrowUpDown, Loader2 } from "lucide-react";
22+
import { useQueryClient } from "@tanstack/react-query";
2323
import {
2424
DropdownMenu,
2525
DropdownMenuContent,
@@ -36,6 +36,8 @@ import {
3636
PaginationPrevious,
3737
} from "@/components/ui/pagination";
3838

39+
import { useClients } from "@/core/hooks/useClients";
40+
3941
const ITEMS_PER_PAGE = 8;
4042

4143
const formatDate = (dateString: string | undefined): string => {
@@ -54,8 +56,6 @@ const formatDate = (dateString: string | undefined): string => {
5456
};
5557

5658
const ClientManagement = () => {
57-
const [clients, setClients] = useState<Client[]>([]);
58-
const [loading, setLoading] = useState(false);
5959
const [selectedClient, setSelectedClient] = useState<Client | null>(null);
6060
const [activateDialogOpen, setActivateDialogOpen] = useState(false);
6161
const [deactivateDialogOpen, setDeactivateDialogOpen] = useState(false);
@@ -64,26 +64,8 @@ const ClientManagement = () => {
6464
const [sortField, setSortField] = useState<keyof Client>("name");
6565
const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc");
6666
const { toast } = useToast();
67-
68-
const fetchClients = async () => {
69-
setLoading(true);
70-
try {
71-
const response = await getClientsApi();
72-
setClients(response.clients);
73-
} catch (error) {
74-
toast({
75-
title: "Error",
76-
description: "Failed to fetch clients",
77-
variant: "destructive",
78-
});
79-
} finally {
80-
setLoading(false);
81-
}
82-
};
83-
84-
useEffect(() => {
85-
fetchClients();
86-
}, []);
67+
const { clients, isLoading, error } = useClients();
68+
const queryClient = useQueryClient();
8769

8870
const handleActivateDeactivate = async (
8971
clientId: string,
@@ -95,7 +77,7 @@ const ClientManagement = () => {
9577
};
9678
try {
9779
await settings.activateUserClientApi(data);
98-
await fetchClients();
80+
await queryClient.invalidateQueries({ queryKey: ["clients"] });
9981
toast({
10082
title: "Success",
10183
description: `Client ${
@@ -135,7 +117,7 @@ const ClientManagement = () => {
135117
};
136118

137119
const filteredClients = clients.filter(
138-
(client) =>
120+
(client: Client) =>
139121
client.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
140122
(client.user?.email?.toLowerCase().includes(searchQuery.toLowerCase()) ??
141123
false)
@@ -153,9 +135,9 @@ const ClientManagement = () => {
153135
currentPage * ITEMS_PER_PAGE
154136
);
155137

156-
const activatedClients = clients.filter((client) => client.isActive).length;
138+
const activatedClients = clients.filter((client: Client) => client.isActive).length;
157139
const deactivatedClients = clients.filter(
158-
(client) => !client.isActive
140+
(client: Client) => !client.isActive
159141
).length;
160142

161143
const getPageNumbers = () => {
@@ -194,15 +176,14 @@ const ClientManagement = () => {
194176

195177
return (
196178
<div className=" py-2">
197-
{loading ? (
179+
{isLoading ? (
198180
<div className="flex justify-center items-center h-64">
199181
<Loader2 className="h-8 w-8 animate-spin" />
200182
</div>
201183
) : (
202184
<>
203185
<div className="flex justify-between items-center mb-6">
204186
<h1 className="text-2xl font-bold">Client Management</h1>
205-
<Button onClick={fetchClients}>Refresh</Button>
206187
</div>
207188

208189
<div className="grid grid-cols-2 gap-4 mb-6">
@@ -379,4 +360,4 @@ const ClientManagement = () => {
379360
);
380361
};
381362

382-
export default ClientManagement;
363+
export default ClientManagement;

netmanager-app/components/Settings/CreateClientForm.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ import { useToast } from "@/components/ui/use-toast"
1111
interface CreateClientFormProps {
1212
open: boolean
1313
onClose: () => void
14-
onClientCreated: () => void
1514
}
1615

17-
const CreateClientForm: React.FC<CreateClientFormProps> = ({ open, onClose, onClientCreated }) => {
16+
const CreateClientForm: React.FC<CreateClientFormProps> = ({ open, onClose }) => {
1817
const { toast } = useToast()
1918
const userInfo = useAppSelector((state) => state.user.userDetails)
2019
const [clientName, setClientName] = useState('')
@@ -59,7 +58,6 @@ const CreateClientForm: React.FC<CreateClientFormProps> = ({ open, onClose, onCl
5958
title: "Success",
6059
description: "Client created successfully",
6160
})
62-
onClientCreated()
6361
onClose()
6462
}
6563
} catch (error: any) {

netmanager-app/components/Settings/MyProfile.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ export default function MyProfile() {
5858
setError(null);
5959

6060
try {
61-
const response = await users.getUserDetails(currentUser._id);
62-
const userData = response?.users?.[0];
61+
const userData = currentUser;
6362

6463
if (userData) {
6564
setProfile({

netmanager-app/core/apis/settings.ts

+4-9
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,11 @@ interface PasswordData {
2020
const axiosInstance = createAxiosInstance();
2121

2222
export const settings = {
23-
getUserClientsApi: async (userID: string): Promise<Client[]> => {
24-
try {
25-
const response = await axiosInstance.get<Client[]>(`${USERS_MGT_URL}/clients`, {
23+
getUserClientsApi: async (userID: string) => {
24+
return await axiosInstance.get(`${USERS_MGT_URL}/clients`, {
2625
params: { user_id: userID },
27-
});
28-
return response.data;
29-
} catch (error) {
30-
console.error("Error fetching clients:", error);
31-
throw error;
32-
}
26+
})
27+
.then((response) => response.data);
3328
},
3429

3530
createClientApi: async (data: CreateClientData): Promise<Client> => {

netmanager-app/core/hooks/useUserClients.ts

+4-7
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,19 @@ export const useUserClients = () => {
1010

1111

1212
const { data, isLoading, error } = useQuery({
13-
queryKey: ["clients", userDetails?._id,],
13+
queryKey: ["clients", userDetails?._id],
1414
queryFn: () =>
15-
settings.getUserClientsApi(
16-
userDetails?._id || ""
17-
),
15+
settings.getUserClientsApi(userDetails?._id || ""),
1816
onSuccess: (data: any) => {
19-
dispatch(setUserClients(data.clients));
20-
17+
dispatch(setUserClients(data));
2118
},
2219
onError: (error: Error) => {
2320
dispatch(setError(error.message));
2421
},
2522
});
2623

2724
return {
28-
clients: data || [],
25+
clients: data?.clients || [],
2926
isLoading,
3027
error: error as Error | null,
3128
};

netmanager-app/core/hooks/users.ts

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ export const useAuth = () => {
5252
privilege: decoded.privilege,
5353
country: decoded.country,
5454
profilePicture: decoded.profilePicture,
55+
description: decoded.description,
56+
timezone: decoded.timezone,
5557
phoneNumber: decoded.phoneNumber,
5658
createdAt: decoded.createdAt,
5759
updatedAt: decoded.updatedAt,

netmanager-app/core/redux/slices/clientsSlice.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const initialState: ClientsState = {
1515
clients: [],
1616
isLoading: false,
1717
clientsDetails: [],
18-
accees_token: [],
18+
access_token: [],
1919
refresh: false,
2020
error: null,
2121
};

0 commit comments

Comments
 (0)