@vtex/faststore-plugin-buyer-portal 1.1.72-experimental.4 → 1.1.72-experimental.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/features/org-units/services/get-org-unit-basic-data.service.ts +1 -34
- package/src/features/shared/utils/cookie.ts +1 -43
- package/src/features/users/layouts/UserDetailsLayout/UserDetailsLayout.tsx +7 -5
- package/src/pages/user-details.tsx +41 -348
- package/DEBUG-500-GUIDE.md +0 -253
- package/src/features/shared/utils/debug.ts +0 -157
package/package.json
CHANGED
|
@@ -7,38 +7,5 @@ export const getOrgUnitBasicDataService = async ({
|
|
|
7
7
|
id: string;
|
|
8
8
|
cookie: string;
|
|
9
9
|
}) => {
|
|
10
|
-
|
|
11
|
-
console.log("[DEBUG] getOrgUnitBasicDataService called:", {
|
|
12
|
-
id,
|
|
13
|
-
hasCookie: !!cookie,
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
if (!id) {
|
|
17
|
-
console.error("[ERROR] getOrgUnitBasicDataService: missing id");
|
|
18
|
-
throw new Error("Organization Unit ID is required");
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (!cookie) {
|
|
22
|
-
console.error("[ERROR] getOrgUnitBasicDataService: missing cookie");
|
|
23
|
-
throw new Error("Authentication cookie is required");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const result = await orgUnitClient.getOrgUnitBasicData(id, cookie);
|
|
27
|
-
|
|
28
|
-
console.log("[DEBUG] getOrgUnitBasicDataService result:", {
|
|
29
|
-
success: !!result,
|
|
30
|
-
orgUnitName: result?.name,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
return result;
|
|
34
|
-
} catch (error) {
|
|
35
|
-
console.error("[ERROR] getOrgUnitBasicDataService failed:", {
|
|
36
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
37
|
-
id,
|
|
38
|
-
hasCookie: !!cookie,
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// Return null instead of throwing to prevent 500 - let caller handle
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
10
|
+
return orgUnitClient.getOrgUnitBasicData(id, cookie);
|
|
44
11
|
};
|
|
@@ -91,47 +91,5 @@ export function getCookieAsString(cookie: Record<string, string>): string {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
function parseJwt(token: string): ParsedCookie {
|
|
94
|
-
|
|
95
|
-
if (!token || typeof token !== "string") {
|
|
96
|
-
console.error("[ERROR] Invalid JWT token:", { token: typeof token });
|
|
97
|
-
throw new Error("Invalid JWT token: token is not a string");
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const parts = token.split(".");
|
|
101
|
-
if (parts.length !== 3) {
|
|
102
|
-
console.error("[ERROR] Invalid JWT format:", {
|
|
103
|
-
partsCount: parts.length,
|
|
104
|
-
});
|
|
105
|
-
throw new Error("Invalid JWT format: expected 3 parts");
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const payload = parts[1];
|
|
109
|
-
if (!payload) {
|
|
110
|
-
console.error("[ERROR] Empty JWT payload");
|
|
111
|
-
throw new Error("Invalid JWT: empty payload");
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
console.log("[DEBUG] Parsing JWT payload...");
|
|
115
|
-
const decoded = JSON.parse(Buffer.from(payload, "base64").toString());
|
|
116
|
-
|
|
117
|
-
console.log("[DEBUG] JWT parsed successfully:", {
|
|
118
|
-
hasUserId: !!decoded.userId,
|
|
119
|
-
hasCustomerId: !!decoded.customerId,
|
|
120
|
-
exp: decoded.exp,
|
|
121
|
-
currentTime: Math.floor(Date.now() / 1000),
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
return decoded;
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.error("[ERROR] JWT parsing failed:", {
|
|
127
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
128
|
-
tokenLength: token?.length || 0,
|
|
129
|
-
tokenPrefix: token?.substring(0, 20) + "...",
|
|
130
|
-
});
|
|
131
|
-
throw new Error(
|
|
132
|
-
`JWT parsing failed: ${
|
|
133
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
134
|
-
}`
|
|
135
|
-
);
|
|
136
|
-
}
|
|
94
|
+
return JSON.parse(Buffer.from(token.split(".")[1], "base64").toString());
|
|
137
95
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Dropdown } from "@faststore/ui";
|
|
2
2
|
|
|
3
|
-
import { useGetRolesOptions } from "../../../roles/hooks";
|
|
3
|
+
// import { useGetRolesOptions } from "../../../roles/hooks"; // Not needed - using props instead
|
|
4
4
|
import {
|
|
5
5
|
BasicDropdownMenu,
|
|
6
6
|
HeaderInside,
|
|
@@ -13,21 +13,23 @@ import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
|
|
|
13
13
|
import { ReassignOrgUnitDrawer, UpdateUserDrawer } from "../../components";
|
|
14
14
|
import { UserDropdownMenu } from "../../components/UserDropdownMenu/UserDropdownMenu";
|
|
15
15
|
|
|
16
|
+
import type { RoleData } from "../../../roles/types";
|
|
16
17
|
import type { UserData } from "../../types/UserData";
|
|
17
18
|
|
|
18
19
|
export type UserDetailsLayoutProps = {
|
|
19
20
|
data: {
|
|
20
21
|
user?: UserData | null;
|
|
21
22
|
orgUnit: { id: string; name: string };
|
|
23
|
+
rolesOptions?: RoleData[] | null;
|
|
22
24
|
};
|
|
23
25
|
};
|
|
24
26
|
|
|
25
27
|
export const UserDetailsLayout = ({
|
|
26
|
-
data: { user },
|
|
28
|
+
data: { user, rolesOptions },
|
|
27
29
|
}: UserDetailsLayoutProps) => {
|
|
28
30
|
const { currentOrgUnit } = useBuyerPortal();
|
|
29
31
|
|
|
30
|
-
const { rolesOptions } = useGetRolesOptions(currentOrgUnit?.id ?? "");
|
|
32
|
+
// const { rolesOptions } = useGetRolesOptions(currentOrgUnit?.id ?? ""); // Using props instead
|
|
31
33
|
|
|
32
34
|
const {
|
|
33
35
|
open: openReassignDrawer,
|
|
@@ -57,7 +59,7 @@ export const UserDetailsLayout = ({
|
|
|
57
59
|
<BasicDropdownMenu.Trigger />
|
|
58
60
|
<UserDropdownMenu
|
|
59
61
|
user={{ name: user?.name ?? "", id: user?.id ?? "" }}
|
|
60
|
-
rolesOptions={rolesOptions}
|
|
62
|
+
rolesOptions={rolesOptions ?? null}
|
|
61
63
|
/>
|
|
62
64
|
</Dropdown>
|
|
63
65
|
</HeaderInside>
|
|
@@ -128,7 +130,7 @@ export const UserDetailsLayout = ({
|
|
|
128
130
|
)}
|
|
129
131
|
{isUpdateUserDrawerOpen && (
|
|
130
132
|
<UpdateUserDrawer
|
|
131
|
-
rolesOptions={rolesOptions}
|
|
133
|
+
rolesOptions={rolesOptions ?? null}
|
|
132
134
|
userId={user?.id ?? ""}
|
|
133
135
|
orgUnitId={currentOrgUnit?.id ?? ""}
|
|
134
136
|
isOpen={isUpdateUserDrawerOpen}
|
|
@@ -2,12 +2,14 @@ import {
|
|
|
2
2
|
getOrgUnitBasicDataService,
|
|
3
3
|
getOrgUnitByUserIdService,
|
|
4
4
|
} from "../features/org-units/services";
|
|
5
|
+
import { getRolesIdsService } from "../features/roles/services";
|
|
5
6
|
import { BuyerPortalProvider } from "../features/shared/components";
|
|
6
7
|
import { type ClientContext, getClientContext } from "../features/shared/utils";
|
|
7
8
|
import { UserDetailsLayout } from "../features/users/layouts";
|
|
8
9
|
import { getUserByIdService } from "../features/users/services/get-user-by-id.service";
|
|
9
10
|
|
|
10
11
|
import type { OrgUnitBasicData } from "../features/org-units/types";
|
|
12
|
+
import type { RoleData } from "../features/roles/types";
|
|
11
13
|
import type { LoaderData } from "../features/shared/types";
|
|
12
14
|
import type { UserData } from "../features/users/types";
|
|
13
15
|
|
|
@@ -20,374 +22,65 @@ export type UserDetailsPageData = {
|
|
|
20
22
|
data: {
|
|
21
23
|
user?: UserData | null;
|
|
22
24
|
orgUnit: { id: string; name: string };
|
|
25
|
+
rolesOptions?: RoleData[] | null;
|
|
23
26
|
};
|
|
24
27
|
context: {
|
|
25
28
|
clientContext: ClientContext;
|
|
26
29
|
currentOrgUnit: OrgUnitBasicData | null;
|
|
27
30
|
currentUser: UserData | null;
|
|
28
31
|
};
|
|
29
|
-
debug?: {
|
|
30
|
-
logs: Array<{
|
|
31
|
-
timestamp: string;
|
|
32
|
-
level: "info" | "error" | "warn";
|
|
33
|
-
step: string;
|
|
34
|
-
message: string;
|
|
35
|
-
data?: any;
|
|
36
|
-
}>;
|
|
37
|
-
error?: any;
|
|
38
|
-
};
|
|
39
32
|
};
|
|
40
33
|
|
|
41
34
|
export async function loader(
|
|
42
35
|
data: LoaderData<UserDetailsPageQuery>
|
|
43
36
|
): Promise<UserDetailsPageData> {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
function addLog(
|
|
47
|
-
level: "info" | "error" | "warn",
|
|
48
|
-
step: string,
|
|
49
|
-
message: string,
|
|
50
|
-
logData?: any
|
|
51
|
-
) {
|
|
52
|
-
const timestamp = new Date().toISOString();
|
|
53
|
-
logs.push({ timestamp, level, step, message, data: logData });
|
|
54
|
-
console.log(
|
|
55
|
-
`🔍 [USER-DETAILS] [${level.toUpperCase()}] ${step}: ${message}`,
|
|
56
|
-
logData || ""
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
addLog("info", "START", "Starting user-details loader");
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
addLog("info", "REQUEST", "Request info", {
|
|
64
|
-
cookies: Object.keys(data.req?.cookies || {}),
|
|
65
|
-
query: data.query,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
addLog("info", "CONTEXT", "Getting client context...");
|
|
69
|
-
const { cookie, ...clientContext } = await getClientContext(data);
|
|
70
|
-
addLog("info", "CONTEXT", "Client context obtained ✅", {
|
|
71
|
-
hasUserId: !!clientContext.userId,
|
|
72
|
-
hasCustomerId: !!clientContext.customerId,
|
|
73
|
-
cookieLength: cookie?.length || 0,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const { userId, orgUnitId } = data.query;
|
|
77
|
-
|
|
78
|
-
if (!userId || !orgUnitId) {
|
|
79
|
-
addLog("error", "VALIDATION", "Missing required query params", {
|
|
80
|
-
userId,
|
|
81
|
-
orgUnitId,
|
|
82
|
-
});
|
|
83
|
-
throw new Error("Missing required query parameters: userId or orgUnitId");
|
|
84
|
-
}
|
|
37
|
+
const { cookie, customerId, ...clientContext } = await getClientContext(data);
|
|
85
38
|
|
|
86
|
-
|
|
87
|
-
userId,
|
|
88
|
-
orgUnitId,
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
addLog("info", "USER_SERVICE", "Fetching user by ID...");
|
|
92
|
-
const user = await getUserByIdService({ orgUnitId, userId, cookie });
|
|
93
|
-
addLog("info", "USER_SERVICE", "User service result", {
|
|
94
|
-
found: !!user,
|
|
95
|
-
email: user?.email,
|
|
96
|
-
});
|
|
39
|
+
const { userId, orgUnitId } = data.query;
|
|
97
40
|
|
|
98
|
-
|
|
99
|
-
addLog("warn", "USER_SERVICE", "User not found - redirecting");
|
|
100
|
-
data.res?.writeHead(302, { Location: "/buyer-portal" });
|
|
101
|
-
data.res?.end();
|
|
41
|
+
const user = await getUserByIdService({ orgUnitId, userId, cookie });
|
|
102
42
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
currentOrgUnit: null,
|
|
108
|
-
currentUser: null,
|
|
109
|
-
},
|
|
110
|
-
debug: {
|
|
111
|
-
logs,
|
|
112
|
-
error: { message: "User not found", userId, orgUnitId },
|
|
113
|
-
},
|
|
114
|
-
};
|
|
115
|
-
}
|
|
43
|
+
if (!user) {
|
|
44
|
+
data.res?.writeHead(302, { Location: "/buyer-portal" });
|
|
45
|
+
data.res?.end();
|
|
46
|
+
}
|
|
116
47
|
|
|
117
|
-
|
|
118
|
-
|
|
48
|
+
const [currentOrgUnit, orgUnitFromUser, rolesOptions] = await Promise.all([
|
|
49
|
+
getOrgUnitBasicDataService({
|
|
119
50
|
id: orgUnitId,
|
|
120
51
|
cookie,
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
found: !!currentOrgUnit,
|
|
124
|
-
name: currentOrgUnit?.name,
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
addLog("info", "ORG_UNIT_USER", "Fetching org unit by user ID...");
|
|
128
|
-
const orgUnitFromUser = await getOrgUnitByUserIdService({
|
|
52
|
+
}),
|
|
53
|
+
getOrgUnitByUserIdService({
|
|
129
54
|
userId,
|
|
130
55
|
cookie,
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
context: {
|
|
148
|
-
clientContext: { cookie, ...clientContext },
|
|
149
|
-
currentOrgUnit,
|
|
150
|
-
currentUser: user,
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
// Só incluir debug se houver erros ou warnings
|
|
155
|
-
const hasIssues = logs.some(
|
|
156
|
-
(log) => log.level === "error" || log.level === "warn"
|
|
157
|
-
);
|
|
158
|
-
if (hasIssues) {
|
|
159
|
-
(result as UserDetailsPageData).debug = { logs };
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return result;
|
|
163
|
-
} catch (error) {
|
|
164
|
-
addLog("error", "FATAL_ERROR", "Loader failed with error", {
|
|
165
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
166
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// Return error page instead of throwing
|
|
170
|
-
return {
|
|
171
|
-
data: { user: null, orgUnit: { id: "", name: "" } },
|
|
172
|
-
context: {
|
|
173
|
-
clientContext: {
|
|
174
|
-
cookie: "",
|
|
175
|
-
vtexIdclientAutCookie: "",
|
|
176
|
-
customerId: "",
|
|
177
|
-
userId: "",
|
|
178
|
-
},
|
|
179
|
-
currentOrgUnit: null,
|
|
180
|
-
currentUser: null,
|
|
181
|
-
},
|
|
182
|
-
debug: {
|
|
183
|
-
logs,
|
|
184
|
-
error:
|
|
185
|
-
error instanceof Error
|
|
186
|
-
? {
|
|
187
|
-
message: error.message,
|
|
188
|
-
name: error.name,
|
|
189
|
-
stack: error.stack,
|
|
190
|
-
}
|
|
191
|
-
: { message: "Unknown error", error },
|
|
56
|
+
}),
|
|
57
|
+
getRolesIdsService({
|
|
58
|
+
unitId: orgUnitId,
|
|
59
|
+
customerId,
|
|
60
|
+
cookie,
|
|
61
|
+
}).catch(() => null), // Gracefully handle errors
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
data: {
|
|
66
|
+
user,
|
|
67
|
+
orgUnit: {
|
|
68
|
+
id: orgUnitFromUser?.id ?? "",
|
|
69
|
+
name: orgUnitFromUser?.name ?? "",
|
|
192
70
|
},
|
|
193
|
-
|
|
194
|
-
|
|
71
|
+
rolesOptions,
|
|
72
|
+
},
|
|
73
|
+
context: {
|
|
74
|
+
clientContext: { cookie, customerId, ...clientContext },
|
|
75
|
+
currentOrgUnit,
|
|
76
|
+
currentUser: user,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
195
79
|
}
|
|
196
80
|
|
|
197
|
-
const UserDetailsPage = ({ data, context
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
style={{
|
|
203
|
-
maxWidth: "900px",
|
|
204
|
-
margin: "0 auto",
|
|
205
|
-
padding: "20px",
|
|
206
|
-
fontFamily: "system-ui, sans-serif",
|
|
207
|
-
}}
|
|
208
|
-
>
|
|
209
|
-
<div
|
|
210
|
-
style={{
|
|
211
|
-
background: "#fff3cd",
|
|
212
|
-
border: "1px solid #ffc107",
|
|
213
|
-
borderRadius: "8px",
|
|
214
|
-
padding: "20px",
|
|
215
|
-
marginBottom: "20px",
|
|
216
|
-
}}
|
|
217
|
-
>
|
|
218
|
-
<h1 style={{ color: "#856404", margin: "0 0 10px 0" }}>
|
|
219
|
-
🚨 Erro na Página User Details
|
|
220
|
-
</h1>
|
|
221
|
-
<p style={{ color: "#856404", margin: 0 }}>
|
|
222
|
-
Ocorreu um erro ao carregar a página. Veja os detalhes abaixo:
|
|
223
|
-
</p>
|
|
224
|
-
</div>
|
|
225
|
-
|
|
226
|
-
{/* Logs em tempo real */}
|
|
227
|
-
<div style={{ marginBottom: "30px" }}>
|
|
228
|
-
<h2
|
|
229
|
-
style={{
|
|
230
|
-
color: "#333",
|
|
231
|
-
borderBottom: "2px solid #007bff",
|
|
232
|
-
paddingBottom: "10px",
|
|
233
|
-
}}
|
|
234
|
-
>
|
|
235
|
-
📝 Logs de Execução
|
|
236
|
-
</h2>
|
|
237
|
-
<div
|
|
238
|
-
style={{
|
|
239
|
-
background: "#1e1e1e",
|
|
240
|
-
color: "#ffffff",
|
|
241
|
-
padding: "20px",
|
|
242
|
-
borderRadius: "8px",
|
|
243
|
-
fontFamily: "Monaco, Consolas, monospace",
|
|
244
|
-
fontSize: "13px",
|
|
245
|
-
maxHeight: "500px",
|
|
246
|
-
overflowY: "auto",
|
|
247
|
-
border: "1px solid #333",
|
|
248
|
-
}}
|
|
249
|
-
>
|
|
250
|
-
{debug.logs.map((log, index) => (
|
|
251
|
-
<div
|
|
252
|
-
key={index}
|
|
253
|
-
style={{
|
|
254
|
-
marginBottom: "12px",
|
|
255
|
-
borderLeft: `4px solid ${
|
|
256
|
-
log.level === "error"
|
|
257
|
-
? "#ff4444"
|
|
258
|
-
: log.level === "warn"
|
|
259
|
-
? "#ff9800"
|
|
260
|
-
: "#4caf50"
|
|
261
|
-
}`,
|
|
262
|
-
paddingLeft: "15px",
|
|
263
|
-
paddingBottom: "8px",
|
|
264
|
-
}}
|
|
265
|
-
>
|
|
266
|
-
<div
|
|
267
|
-
style={{
|
|
268
|
-
color: "#888",
|
|
269
|
-
fontSize: "11px",
|
|
270
|
-
marginBottom: "4px",
|
|
271
|
-
}}
|
|
272
|
-
>
|
|
273
|
-
{new Date(log.timestamp).toLocaleTimeString("pt-BR")} -{" "}
|
|
274
|
-
{log.step}
|
|
275
|
-
</div>
|
|
276
|
-
<div
|
|
277
|
-
style={{
|
|
278
|
-
color:
|
|
279
|
-
log.level === "error"
|
|
280
|
-
? "#ff6b6b"
|
|
281
|
-
: log.level === "warn"
|
|
282
|
-
? "#ffa726"
|
|
283
|
-
: "#81c784",
|
|
284
|
-
fontWeight: "bold",
|
|
285
|
-
marginBottom: log.data ? "8px" : 0,
|
|
286
|
-
}}
|
|
287
|
-
>
|
|
288
|
-
[{log.level.toUpperCase()}] {log.message}
|
|
289
|
-
</div>
|
|
290
|
-
{log.data && (
|
|
291
|
-
<pre
|
|
292
|
-
style={{
|
|
293
|
-
fontSize: "11px",
|
|
294
|
-
color: "#ccc",
|
|
295
|
-
background: "#2d2d2d",
|
|
296
|
-
padding: "8px",
|
|
297
|
-
borderRadius: "4px",
|
|
298
|
-
margin: 0,
|
|
299
|
-
whiteSpace: "pre-wrap",
|
|
300
|
-
overflow: "auto",
|
|
301
|
-
}}
|
|
302
|
-
>
|
|
303
|
-
{JSON.stringify(log.data, null, 2)}
|
|
304
|
-
</pre>
|
|
305
|
-
)}
|
|
306
|
-
</div>
|
|
307
|
-
))}
|
|
308
|
-
</div>
|
|
309
|
-
</div>
|
|
310
|
-
|
|
311
|
-
{/* Detalhes do erro */}
|
|
312
|
-
{debug.error && (
|
|
313
|
-
<div style={{ marginBottom: "30px" }}>
|
|
314
|
-
<h2
|
|
315
|
-
style={{
|
|
316
|
-
color: "#dc3545",
|
|
317
|
-
borderBottom: "2px solid #dc3545",
|
|
318
|
-
paddingBottom: "10px",
|
|
319
|
-
}}
|
|
320
|
-
>
|
|
321
|
-
❌ Detalhes do Erro
|
|
322
|
-
</h2>
|
|
323
|
-
<pre
|
|
324
|
-
style={{
|
|
325
|
-
background: "#f8d7da",
|
|
326
|
-
color: "#721c24",
|
|
327
|
-
padding: "20px",
|
|
328
|
-
borderRadius: "8px",
|
|
329
|
-
border: "1px solid #f5c6cb",
|
|
330
|
-
overflow: "auto",
|
|
331
|
-
fontSize: "13px",
|
|
332
|
-
}}
|
|
333
|
-
>
|
|
334
|
-
{JSON.stringify(debug.error, null, 2)}
|
|
335
|
-
</pre>
|
|
336
|
-
</div>
|
|
337
|
-
)}
|
|
338
|
-
|
|
339
|
-
{/* Próximos passos */}
|
|
340
|
-
<div
|
|
341
|
-
style={{
|
|
342
|
-
background: "#d1ecf1",
|
|
343
|
-
border: "1px solid #bee5eb",
|
|
344
|
-
borderRadius: "8px",
|
|
345
|
-
padding: "20px",
|
|
346
|
-
}}
|
|
347
|
-
>
|
|
348
|
-
<h3 style={{ color: "#0c5460", margin: "0 0 15px 0" }}>
|
|
349
|
-
🔧 Como resolver:
|
|
350
|
-
</h3>
|
|
351
|
-
<ol style={{ color: "#0c5460", paddingLeft: "20px" }}>
|
|
352
|
-
<li>Verifique se você está logado na VTEX</li>
|
|
353
|
-
<li>Confirme se os IDs da URL estão corretos</li>
|
|
354
|
-
<li>Tente fazer logout e login novamente</li>
|
|
355
|
-
<li>Se o erro persistir, entre em contato com o suporte</li>
|
|
356
|
-
</ol>
|
|
357
|
-
|
|
358
|
-
<div
|
|
359
|
-
style={{
|
|
360
|
-
marginTop: "15px",
|
|
361
|
-
padding: "10px",
|
|
362
|
-
background: "#b8daff",
|
|
363
|
-
borderRadius: "4px",
|
|
364
|
-
}}
|
|
365
|
-
>
|
|
366
|
-
<strong>💡 Dica:</strong> Abra o console do browser (F12) para ver
|
|
367
|
-
logs adicionais
|
|
368
|
-
</div>
|
|
369
|
-
</div>
|
|
370
|
-
|
|
371
|
-
<script
|
|
372
|
-
dangerouslySetInnerHTML={{
|
|
373
|
-
__html: `
|
|
374
|
-
// Log debug info to browser console
|
|
375
|
-
console.group('🔍 USER DETAILS DEBUG INFO');
|
|
376
|
-
console.log('Error Details:', ${JSON.stringify(debug.error)});
|
|
377
|
-
console.log('Execution Logs:', ${JSON.stringify(debug.logs)});
|
|
378
|
-
console.groupEnd();
|
|
379
|
-
`,
|
|
380
|
-
}}
|
|
381
|
-
/>
|
|
382
|
-
</div>
|
|
383
|
-
);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Se não tiver debug info, mostrar página normal
|
|
387
|
-
return (
|
|
388
|
-
<BuyerPortalProvider {...context}>
|
|
389
|
-
<UserDetailsLayout data={data} />
|
|
390
|
-
</BuyerPortalProvider>
|
|
391
|
-
);
|
|
392
|
-
};
|
|
81
|
+
const UserDetailsPage = ({ data, context }: UserDetailsPageData) => (
|
|
82
|
+
<BuyerPortalProvider {...context}>
|
|
83
|
+
<UserDetailsLayout data={data} />
|
|
84
|
+
</BuyerPortalProvider>
|
|
85
|
+
);
|
|
393
86
|
export default UserDetailsPage;
|
package/DEBUG-500-GUIDE.md
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
# 🚨 Guia de Debug - Erro 500 na Página User Details
|
|
2
|
-
|
|
3
|
-
## ✅ **O que foi implementado:**
|
|
4
|
-
|
|
5
|
-
### 1. **Logging Detalhado**
|
|
6
|
-
|
|
7
|
-
- ✅ Adicionado logging extensivo no loader `user-details.tsx`
|
|
8
|
-
- ✅ Melhorado parsing JWT com validação robusta
|
|
9
|
-
- ✅ Tratamento de erro em `getOrgUnitBasicDataService`
|
|
10
|
-
- ✅ Criado utilitários de debug (`debug.ts`)
|
|
11
|
-
|
|
12
|
-
### 2. **Página de Debug**
|
|
13
|
-
|
|
14
|
-
- ✅ Criada página temporária `/buyer-portal/debug-user-details/[orgUnitId]/[userId]`
|
|
15
|
-
- ✅ Adicionada rota no `plugin.config.js`
|
|
16
|
-
- ✅ Interface visual para troubleshooting
|
|
17
|
-
|
|
18
|
-
## 🔍 **Como debugar o erro 500:**
|
|
19
|
-
|
|
20
|
-
### **Passo 1: Acesse a página problemática**
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
https://seusite.com/buyer-portal/user/[orgUnitId]/[userId]
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
**Substitua:**
|
|
27
|
-
|
|
28
|
-
- `[orgUnitId]` pelo ID da org unit problemática
|
|
29
|
-
- `[userId]` pelo ID do usuário que está causando erro
|
|
30
|
-
|
|
31
|
-
**IMPORTANTE:** Quando houver erro, a página vai mostrar **automaticamente** uma tela de debug com todos os logs!
|
|
32
|
-
|
|
33
|
-
### **Passo 2: Analise os logs (DIRETO NA PÁGINA! 🎉)**
|
|
34
|
-
|
|
35
|
-
**IMPORTANTE:** Agora os logs aparecem **diretamente na página de debug**! Não precisa acessar servidor!
|
|
36
|
-
|
|
37
|
-
Na página debug você verá:
|
|
38
|
-
|
|
39
|
-
- 📝 **Execution Logs (Real-time)** - Uma seção com todos os logs do processo
|
|
40
|
-
- ✅ Logs verdes: operações que funcionaram
|
|
41
|
-
- ⚠️ Logs amarelos: avisos
|
|
42
|
-
- ❌ Logs vermelhos: erros
|
|
43
|
-
|
|
44
|
-
**Exemplo do que você vai ver:**
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
14:30:25 - START
|
|
48
|
-
[INFO] Starting debug loader
|
|
49
|
-
|
|
50
|
-
14:30:25 - VALIDATION
|
|
51
|
-
[INFO] Request validation passed ✅
|
|
52
|
-
|
|
53
|
-
14:30:25 - CONTEXT
|
|
54
|
-
[INFO] Client context obtained ✅
|
|
55
|
-
{ hasUserId: true, cookieLength: 234 }
|
|
56
|
-
|
|
57
|
-
14:30:26 - USER_SERVICE
|
|
58
|
-
[ERROR] User service failed
|
|
59
|
-
{ error: "JWT parsing failed", tokenLength: 0 }
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### **Passo 3: Verifique pontos críticos**
|
|
63
|
-
|
|
64
|
-
#### **3.1 Cookies de Autenticação**
|
|
65
|
-
|
|
66
|
-
```javascript
|
|
67
|
-
// Procure por este log:
|
|
68
|
-
[DEBUG] JWT parsed successfully: { hasUserId: true, hasCustomerId: true }
|
|
69
|
-
|
|
70
|
-
// Se aparecer erro:
|
|
71
|
-
[ERROR] JWT parsing failed
|
|
72
|
-
[ERROR] Invalid JWT token
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
#### **3.2 APIs da VTEX**
|
|
76
|
-
|
|
77
|
-
```javascript
|
|
78
|
-
// Procure por:
|
|
79
|
-
[DEBUG] getOrgUnitBasicDataService called
|
|
80
|
-
[ERROR] getOrgUnitBasicDataService failed
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
#### **3.3 Parâmetros da URL**
|
|
84
|
-
|
|
85
|
-
```javascript
|
|
86
|
-
// Deve aparecer:
|
|
87
|
-
[DEBUG] user-details loader started: { query: { userId: "123", orgUnitId: "456" } }
|
|
88
|
-
|
|
89
|
-
// Se não tiver userId ou orgUnitId, vai dar erro:
|
|
90
|
-
[ERROR] Missing required query parameters
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## 🎯 **Cenários mais comuns:**
|
|
94
|
-
|
|
95
|
-
### **Erro 1: Cookie JWT inválido/expirado**
|
|
96
|
-
|
|
97
|
-
**Sintomas:**
|
|
98
|
-
|
|
99
|
-
- `[ERROR] JWT parsing failed`
|
|
100
|
-
- `[ERROR] Invalid JWT token`
|
|
101
|
-
|
|
102
|
-
**Solução:**
|
|
103
|
-
|
|
104
|
-
- Usuário precisa fazer login novamente
|
|
105
|
-
- Verificar se o cookie `VtexIdclientAutCookie_[storeId]` existe
|
|
106
|
-
|
|
107
|
-
### **Erro 2: API VTEX indisponível**
|
|
108
|
-
|
|
109
|
-
**Sintomas:**
|
|
110
|
-
|
|
111
|
-
- `[ERROR] getOrgUnitBasicDataService failed`
|
|
112
|
-
- `[ERROR] getUserByIdService failed`
|
|
113
|
-
|
|
114
|
-
**Solução:**
|
|
115
|
-
|
|
116
|
-
- Verificar conectividade com APIs da VTEX
|
|
117
|
-
- Verificar se `storeConfig.api.storeId` está correto
|
|
118
|
-
|
|
119
|
-
### **Erro 3: Parâmetros de URL inválidos**
|
|
120
|
-
|
|
121
|
-
**Sintomas:**
|
|
122
|
-
|
|
123
|
-
- `[ERROR] Missing required query parameters`
|
|
124
|
-
- `[DEBUG] User service result: { userFound: false }`
|
|
125
|
-
|
|
126
|
-
**Solução:**
|
|
127
|
-
|
|
128
|
-
- Verificar se userId e orgUnitId são válidos
|
|
129
|
-
- Testar com IDs conhecidos que funcionam
|
|
130
|
-
|
|
131
|
-
### **Erro 4: Discovery Config**
|
|
132
|
-
|
|
133
|
-
**Sintomas:**
|
|
134
|
-
|
|
135
|
-
- Erro ao construir URLs de API
|
|
136
|
-
- `storeConfig is undefined`
|
|
137
|
-
|
|
138
|
-
**Solução:**
|
|
139
|
-
|
|
140
|
-
- Verificar se `discovery.config` está presente
|
|
141
|
-
- Verificar configurações da store
|
|
142
|
-
|
|
143
|
-
## 🛠️ **Comandos úteis para debug:**
|
|
144
|
-
|
|
145
|
-
### **1. Ver logs no Browser Console (FÁCIL!):**
|
|
146
|
-
|
|
147
|
-
```bash
|
|
148
|
-
# Abra DevTools (F12) no Chrome/Firefox
|
|
149
|
-
# Vá na aba Console
|
|
150
|
-
# Procure por logs que começam com:
|
|
151
|
-
🔍 [BUYER-PORTAL-DEBUG]
|
|
152
|
-
|
|
153
|
-
# Exemplo do que vai aparecer:
|
|
154
|
-
🔍 [BUYER-PORTAL-DEBUG] CONTEXT: Getting client context...
|
|
155
|
-
🔍 [BUYER-PORTAL-DEBUG] USER_SERVICE: Fetching user by ID...
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### **2. Ver logs do servidor (se tiver acesso):**
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
# Tail nos logs do Next.js
|
|
162
|
-
tail -f /caminho/para/logs/nextjs.log | grep -E "(DEBUG|ERROR)"
|
|
163
|
-
|
|
164
|
-
# Ou se usando PM2:
|
|
165
|
-
pm2 logs | grep -E "(DEBUG|ERROR)"
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### **3. Testar APIs manualmente:**
|
|
169
|
-
|
|
170
|
-
```bash
|
|
171
|
-
# Teste a API de usuário:
|
|
172
|
-
curl -H "Cookie: VtexIdclientAutCookie_[storeId]=TOKEN" \
|
|
173
|
-
"https://[storeId].myvtex.com/_v/store-front/users/[orgUnitId]/[userId]"
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### **4. Verificar configurações:**
|
|
177
|
-
|
|
178
|
-
```javascript
|
|
179
|
-
// No browser console (dev tools):
|
|
180
|
-
console.log("Store Config:", window.storeConfig);
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
## 📊 **Informações importantes da página de debug:**
|
|
184
|
-
|
|
185
|
-
### **JSON Debug Response:**
|
|
186
|
-
|
|
187
|
-
```json
|
|
188
|
-
{
|
|
189
|
-
"success": false,
|
|
190
|
-
"debug": {
|
|
191
|
-
"timestamp": "2024-01-01T12:00:00.000Z",
|
|
192
|
-
"cookies": {
|
|
193
|
-
"cookieKeys": ["session", "VtexIdclientAutCookie_store"],
|
|
194
|
-
"vtexAuthCookie": true
|
|
195
|
-
},
|
|
196
|
-
"query": { "userId": "123", "orgUnitId": "456" }
|
|
197
|
-
},
|
|
198
|
-
"error": {
|
|
199
|
-
"message": "JWT parsing failed",
|
|
200
|
-
"name": "Error"
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
## 🚀 **Após identificar o problema:**
|
|
206
|
-
|
|
207
|
-
### **1. Remover arquivos de debug (IMPORTANTE!):**
|
|
208
|
-
|
|
209
|
-
```bash
|
|
210
|
-
rm src/pages/debug-user-details.tsx
|
|
211
|
-
rm src/features/shared/utils/debug.ts
|
|
212
|
-
rm DEBUG-500-GUIDE.md
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### **2. Remover rota debug do plugin.config.js**
|
|
216
|
-
|
|
217
|
-
### **3. Limpar logs de produção:**
|
|
218
|
-
|
|
219
|
-
- Remover/comentar console.log em produção
|
|
220
|
-
- Manter apenas logs de erro essenciais
|
|
221
|
-
|
|
222
|
-
## 🆘 **Se ainda não conseguir resolver:**
|
|
223
|
-
|
|
224
|
-
### **Colete estas informações:**
|
|
225
|
-
|
|
226
|
-
1. **Logs completos** da página de debug
|
|
227
|
-
2. **URL exata** que está falhando
|
|
228
|
-
3. **Browser e versão** do usuário
|
|
229
|
-
4. **Horário específico** do erro
|
|
230
|
-
5. **Se funciona em desenvolvimento** mas não em produção
|
|
231
|
-
|
|
232
|
-
### **Pontos adicionais para investigar:**
|
|
233
|
-
|
|
234
|
-
- **Rate limiting** das APIs da VTEX
|
|
235
|
-
- **Configurações de CORS**
|
|
236
|
-
- **Certificados SSL**
|
|
237
|
-
- **Timeout de requests**
|
|
238
|
-
- **Configurações de proxy/CDN**
|
|
239
|
-
|
|
240
|
-
## 📝 **Checklist de debug:**
|
|
241
|
-
|
|
242
|
-
- [ ] Página de debug criada e testada
|
|
243
|
-
- [ ] Logs do servidor coletados
|
|
244
|
-
- [ ] Cookies de auth verificados
|
|
245
|
-
- [ ] APIs da VTEX testadas manualmente
|
|
246
|
-
- [ ] Parâmetros de URL validados
|
|
247
|
-
- [ ] Discovery config verificado
|
|
248
|
-
- [ ] Diferenças dev vs prod identificadas
|
|
249
|
-
- [ ] Arquivos de debug removidos após solução
|
|
250
|
-
|
|
251
|
-
---
|
|
252
|
-
|
|
253
|
-
**⚡ Dica:** A página de debug é sua melhor ferramenta - ela vai te mostrar exatamente onde está falhando!
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Debug utilities for production troubleshooting
|
|
3
|
-
* Use these functions to gather information when debugging 500 errors
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface DebugInfo {
|
|
7
|
-
timestamp: string;
|
|
8
|
-
url?: string;
|
|
9
|
-
userAgent?: string;
|
|
10
|
-
cookies: Record<string, any>;
|
|
11
|
-
headers?: Record<string, any>;
|
|
12
|
-
query?: Record<string, any>;
|
|
13
|
-
environment: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function getDebugInfo(req?: any, query?: any): DebugInfo {
|
|
17
|
-
return {
|
|
18
|
-
timestamp: new Date().toISOString(),
|
|
19
|
-
url: req?.url,
|
|
20
|
-
userAgent: req?.headers?.["user-agent"],
|
|
21
|
-
cookies: {
|
|
22
|
-
cookieKeys: Object.keys(req?.cookies || {}),
|
|
23
|
-
hasCookies: !!(req?.cookies && Object.keys(req.cookies).length > 0),
|
|
24
|
-
vtexAuthCookie: !!(
|
|
25
|
-
req?.cookies?.VtexIdclientAutCookie ||
|
|
26
|
-
Object.keys(req?.cookies || {}).find((key) =>
|
|
27
|
-
key.includes("VtexIdclientAutCookie")
|
|
28
|
-
)
|
|
29
|
-
),
|
|
30
|
-
},
|
|
31
|
-
headers: {
|
|
32
|
-
hasAuthorization: !!req?.headers?.authorization,
|
|
33
|
-
contentType: req?.headers?.["content-type"],
|
|
34
|
-
origin: req?.headers?.origin,
|
|
35
|
-
},
|
|
36
|
-
query,
|
|
37
|
-
environment: process.env.NODE_ENV || "unknown",
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function logDebugInfo(info: DebugInfo, context: string = "DEBUG") {
|
|
42
|
-
console.log(`[${context}] Debug Info:`, JSON.stringify(info, null, 2));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Browser-safe logging that works on both client and server
|
|
47
|
-
*/
|
|
48
|
-
export function logToBrowser(
|
|
49
|
-
message: string,
|
|
50
|
-
data?: any,
|
|
51
|
-
level: "info" | "error" | "warn" = "info"
|
|
52
|
-
) {
|
|
53
|
-
if (typeof window !== "undefined") {
|
|
54
|
-
// Client-side: log to browser console
|
|
55
|
-
const logFunc =
|
|
56
|
-
level === "error"
|
|
57
|
-
? console.error
|
|
58
|
-
: level === "warn"
|
|
59
|
-
? console.warn
|
|
60
|
-
: console.log;
|
|
61
|
-
logFunc(`🔍 [BUYER-PORTAL-DEBUG] ${message}`, data || "");
|
|
62
|
-
} else {
|
|
63
|
-
// Server-side: still log to server console
|
|
64
|
-
const logFunc =
|
|
65
|
-
level === "error"
|
|
66
|
-
? console.error
|
|
67
|
-
: level === "warn"
|
|
68
|
-
? console.warn
|
|
69
|
-
: console.log;
|
|
70
|
-
logFunc(`🔍 [BUYER-PORTAL-DEBUG] ${message}`, data || "");
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Safe function to extract error details without exposing sensitive data
|
|
76
|
-
*/
|
|
77
|
-
export function sanitizeError(error: unknown): Record<string, any> {
|
|
78
|
-
if (error instanceof Error) {
|
|
79
|
-
return {
|
|
80
|
-
name: error.name,
|
|
81
|
-
message: error.message,
|
|
82
|
-
stack:
|
|
83
|
-
process.env.NODE_ENV === "development"
|
|
84
|
-
? error.stack
|
|
85
|
-
: "Hidden in production",
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (typeof error === "string") {
|
|
90
|
-
return { message: error };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return { message: "Unknown error type", type: typeof error };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Create a debug endpoint response for troubleshooting
|
|
98
|
-
*/
|
|
99
|
-
export function createDebugResponse(req?: any, error?: unknown) {
|
|
100
|
-
const debugInfo = getDebugInfo(req);
|
|
101
|
-
const errorInfo = error ? sanitizeError(error) : null;
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
debug: debugInfo,
|
|
105
|
-
error: errorInfo,
|
|
106
|
-
suggestions: [
|
|
107
|
-
"Check if authentication cookies are present and valid",
|
|
108
|
-
"Verify VTEX API endpoints are accessible",
|
|
109
|
-
"Ensure required query parameters are provided",
|
|
110
|
-
"Check server logs for more detailed error information",
|
|
111
|
-
],
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Validate essential request data
|
|
117
|
-
*/
|
|
118
|
-
export function validateRequest(
|
|
119
|
-
req?: any,
|
|
120
|
-
requiredQuery: string[] = []
|
|
121
|
-
): {
|
|
122
|
-
isValid: boolean;
|
|
123
|
-
errors: string[];
|
|
124
|
-
} {
|
|
125
|
-
const errors: string[] = [];
|
|
126
|
-
|
|
127
|
-
if (!req) {
|
|
128
|
-
errors.push("Request object is missing");
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (!req?.cookies || Object.keys(req.cookies).length === 0) {
|
|
132
|
-
errors.push("No cookies found in request");
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Check for VTEX auth cookie
|
|
136
|
-
const hasVtexAuth =
|
|
137
|
-
req?.cookies &&
|
|
138
|
-
Object.keys(req.cookies).some((key) =>
|
|
139
|
-
key.includes("VtexIdclientAutCookie")
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
if (!hasVtexAuth) {
|
|
143
|
-
errors.push("VTEX authentication cookie not found");
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Check required query parameters
|
|
147
|
-
for (const param of requiredQuery) {
|
|
148
|
-
if (!req?.query?.[param]) {
|
|
149
|
-
errors.push(`Required query parameter missing: ${param}`);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
isValid: errors.length === 0,
|
|
155
|
-
errors,
|
|
156
|
-
};
|
|
157
|
-
}
|