@stackoverflow/backstage-plugin-stack-overflow-teams 1.6.2 → 1.6.3

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.
Files changed (57) hide show
  1. package/dist/api/StackOverflowAPI.esm.js +125 -0
  2. package/dist/api/StackOverflowAPI.esm.js.map +1 -0
  3. package/dist/components/StackOverflow/StackOverflowMe.esm.js +125 -0
  4. package/dist/components/StackOverflow/StackOverflowMe.esm.js.map +1 -0
  5. package/dist/components/StackOverflow/StackOverflowPostQuestionModal.esm.js +803 -0
  6. package/dist/components/StackOverflow/StackOverflowPostQuestionModal.esm.js.map +1 -0
  7. package/dist/components/StackOverflow/StackOverflowPosts.esm.js +444 -0
  8. package/dist/components/StackOverflow/StackOverflowPosts.esm.js.map +1 -0
  9. package/dist/components/StackOverflow/StackOverflowSearchResultListItem.esm.js +175 -0
  10. package/dist/components/StackOverflow/StackOverflowSearchResultListItem.esm.js.map +1 -0
  11. package/dist/components/StackOverflow/StackOverflowTags.esm.js +127 -0
  12. package/dist/components/StackOverflow/StackOverflowTags.esm.js.map +1 -0
  13. package/dist/components/StackOverflow/StackOverflowUsers.esm.js +226 -0
  14. package/dist/components/StackOverflow/StackOverflowUsers.esm.js.map +1 -0
  15. package/dist/components/StackOverflow/TiptapEditor.esm.js +312 -0
  16. package/dist/components/StackOverflow/TiptapEditor.esm.js.map +1 -0
  17. package/dist/components/StackOverflow/hooks/useStackOverflowData.esm.js +128 -0
  18. package/dist/components/StackOverflow/hooks/useStackOverflowData.esm.js.map +1 -0
  19. package/dist/components/StackOverflow/hooks/useStackOverflowSearch.esm.js +53 -0
  20. package/dist/components/StackOverflow/hooks/useStackOverflowSearch.esm.js.map +1 -0
  21. package/dist/components/StackOverflow/hooks/useStackOverflowStyles.esm.js +39 -0
  22. package/dist/components/StackOverflow/hooks/useStackOverflowStyles.esm.js.map +1 -0
  23. package/dist/components/StackOverflowAuth/StackAuthCallback.esm.js +48 -0
  24. package/dist/components/StackOverflowAuth/StackAuthCallback.esm.js.map +1 -0
  25. package/dist/components/StackOverflowAuth/StackAuthFailed.esm.js +38 -0
  26. package/dist/components/StackOverflowAuth/StackAuthFailed.esm.js.map +1 -0
  27. package/dist/components/StackOverflowAuth/StackAuthLoading.esm.js +22 -0
  28. package/dist/components/StackOverflowAuth/StackAuthLoading.esm.js.map +1 -0
  29. package/dist/components/StackOverflowAuth/StackAuthStart.esm.js +238 -0
  30. package/dist/components/StackOverflowAuth/StackAuthStart.esm.js.map +1 -0
  31. package/dist/components/StackOverflowAuth/StackAuthSuccess.esm.js +40 -0
  32. package/dist/components/StackOverflowAuth/StackAuthSuccess.esm.js.map +1 -0
  33. package/dist/icons/LogoutIcon.esm.js +24 -0
  34. package/dist/icons/LogoutIcon.esm.js.map +1 -0
  35. package/dist/icons/StackOverflowIcon.esm.js +27 -0
  36. package/dist/icons/StackOverflowIcon.esm.js.map +1 -0
  37. package/dist/index.d.ts +47 -0
  38. package/dist/index.esm.js +19 -0
  39. package/dist/index.esm.js.map +1 -0
  40. package/dist/package.json.esm.js +6 -0
  41. package/dist/package.json.esm.js.map +1 -0
  42. package/dist/pages/StackOverflowHub.esm.js +138 -0
  43. package/dist/pages/StackOverflowHub.esm.js.map +1 -0
  44. package/dist/pages/StackOverflowTeamsPage.esm.js +43 -0
  45. package/dist/pages/StackOverflowTeamsPage.esm.js.map +1 -0
  46. package/dist/pages/index.esm.js +3 -0
  47. package/dist/pages/index.esm.js.map +1 -0
  48. package/dist/plugin.esm.js +27 -0
  49. package/dist/plugin.esm.js.map +1 -0
  50. package/dist/routes.esm.js +8 -0
  51. package/dist/routes.esm.js.map +1 -0
  52. package/dist/utils/decodeHtml.esm.js +8 -0
  53. package/dist/utils/decodeHtml.esm.js.map +1 -0
  54. package/dist/utils/getTimeAgo.esm.js +30 -0
  55. package/dist/utils/getTimeAgo.esm.js.map +1 -0
  56. package/package.json +12 -4
  57. package/src/index.ts +0 -5
@@ -0,0 +1,125 @@
1
+ import { createApiRef } from '@backstage/core-plugin-api';
2
+
3
+ const stackoverflowteamsApiRef = createApiRef({
4
+ id: "plugin.stackoverflowteams.api"
5
+ });
6
+ const createStackOverflowApi = (discoveryApi, fetchApi) => {
7
+ const getBaseUrl = async () => discoveryApi.getBaseUrl("stack-overflow-teams");
8
+ const requestAPI = async (endpoint, method = "GET", body, params) => {
9
+ const baseUrl = await getBaseUrl();
10
+ const queryString = params ? `?${params.join("&")}` : "";
11
+ const url = `${baseUrl}/${endpoint}${queryString}`;
12
+ const response = await fetchApi.fetch(url, {
13
+ method,
14
+ credentials: "include",
15
+ headers: { "Content-Type": "application/json" },
16
+ body: body ? JSON.stringify(body) : void 0
17
+ });
18
+ if (!response.ok) {
19
+ const errorResponse = await response.json();
20
+ throw new Error(errorResponse.error || `Request failed: ${response.statusText}`);
21
+ }
22
+ return response.json();
23
+ };
24
+ const buildQuestionParams = (filter) => {
25
+ const params = [];
26
+ if (filter?.sort) {
27
+ params.push(`sort=${filter.sort}`);
28
+ }
29
+ if (filter?.order) {
30
+ params.push(`order=${filter.order}`);
31
+ }
32
+ if (filter?.isAnswered !== void 0) {
33
+ params.push(`isAnswered=${filter.isAnswered}`);
34
+ }
35
+ if (filter?.page !== void 0) {
36
+ params.push(`page=${filter.page}`);
37
+ }
38
+ if (filter?.pageSize !== void 0) {
39
+ params.push(`pageSize=${filter.pageSize}`);
40
+ }
41
+ return params;
42
+ };
43
+ return {
44
+ search: (query, page) => {
45
+ const body = { query };
46
+ if (page !== void 0) {
47
+ body.page = page;
48
+ }
49
+ return requestAPI("search", "POST", body);
50
+ },
51
+ getQuestions: (filter) => {
52
+ const params = buildQuestionParams(filter);
53
+ return requestAPI("questions", "GET", void 0, params.length > 0 ? params : void 0);
54
+ },
55
+ getTags: (search) => {
56
+ const params = search ? [`search=${encodeURIComponent(search)}`] : void 0;
57
+ return requestAPI("tags", "GET", void 0, params);
58
+ },
59
+ getUsers: () => requestAPI("users"),
60
+ getMe: () => requestAPI("me"),
61
+ getBaseUrl: async () => {
62
+ const response = await requestAPI("baseurl");
63
+ return response.SOInstance;
64
+ },
65
+ getTeamName: async () => {
66
+ const response = await requestAPI("baseurl");
67
+ return response.teamName;
68
+ },
69
+ postQuestion: (title, body, tags) => requestAPI("questions", "POST", { title, body, tags }),
70
+ startAuth: async () => {
71
+ const data = await requestAPI("auth/start");
72
+ return data.authUrl;
73
+ },
74
+ completeAuth: async (code, state) => {
75
+ await requestAPI("callback", "GET", void 0, [
76
+ `code=${encodeURIComponent(code)}`,
77
+ `state=${encodeURIComponent(state)}`
78
+ ]);
79
+ },
80
+ getAuthStatus: async () => {
81
+ try {
82
+ await requestAPI("authStatus");
83
+ return true;
84
+ } catch {
85
+ return false;
86
+ }
87
+ },
88
+ logout: async () => {
89
+ try {
90
+ await requestAPI("logout", "POST");
91
+ return true;
92
+ } catch {
93
+ return false;
94
+ }
95
+ },
96
+ submitAccessToken: async (token) => {
97
+ try {
98
+ await requestAPI("auth/token", "POST", { accessToken: token });
99
+ return true;
100
+ } catch {
101
+ return false;
102
+ }
103
+ },
104
+ // Convenience methods for common filtering scenarios
105
+ getActiveQuestions: (page) => {
106
+ const params = buildQuestionParams({ sort: "activity", order: "desc", page });
107
+ return requestAPI("questions", "GET", void 0, params);
108
+ },
109
+ getNewestQuestions: (page) => {
110
+ const params = buildQuestionParams({ sort: "creation", order: "desc", page });
111
+ return requestAPI("questions", "GET", void 0, params);
112
+ },
113
+ getTopScoredQuestions: (page) => {
114
+ const params = buildQuestionParams({ sort: "score", order: "desc", page });
115
+ return requestAPI("questions", "GET", void 0, params);
116
+ },
117
+ getUnansweredQuestions: (page) => {
118
+ const params = buildQuestionParams({ isAnswered: false, sort: "creation", order: "desc", page });
119
+ return requestAPI("questions", "GET", void 0, params);
120
+ }
121
+ };
122
+ };
123
+
124
+ export { createStackOverflowApi, stackoverflowteamsApiRef };
125
+ //# sourceMappingURL=StackOverflowAPI.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StackOverflowAPI.esm.js","sources":["../../src/api/StackOverflowAPI.ts"],"sourcesContent":["import {\n createApiRef,\n DiscoveryApi,\n FetchApi,\n} from '@backstage/core-plugin-api';\nimport { Question, Tag, User, PaginatedResponse } from '../api';\n\nexport const stackoverflowteamsApiRef = createApiRef<StackOverflowAPI>({\n id: 'plugin.stackoverflowteams.api',\n});\n\ntype ApiResponse<T> = PaginatedResponse<T>;\n\ninterface BaseUrlResponse {\n SOInstance: string;\n teamName: string\n}\n\n// Enhanced interface for questions filter options\ninterface QuestionsFilter {\n sort?: 'activity' | 'creation' | 'score';\n order?: 'asc' | 'desc';\n isAnswered?: boolean;\n page?: number;\n pageSize?: number;\n}\n\nexport interface StackOverflowAPI {\n search(query: string, page?: number): Promise<any>;\n getQuestions(filter?: QuestionsFilter): Promise<ApiResponse<Question>>;\n getTags(search?: string): Promise<ApiResponse<Tag>>;\n getUsers(): Promise<ApiResponse<User>>;\n getMe(): Promise<User>;\n getBaseUrl(): Promise<string>;\n getTeamName(): Promise<string>;\n postQuestion(title: string, body: string, tags: string[]): Promise<Question>;\n startAuth(): Promise<string>;\n completeAuth(code: string, state: string): Promise<void>;\n getAuthStatus: () => Promise<boolean>;\n logout: () => Promise<boolean>;\n submitAccessToken: (token: string) => Promise<boolean>;\n \n // Convenience methods for common filtering scenarios\n getActiveQuestions(page?: number): Promise<ApiResponse<Question>>;\n getNewestQuestions(page?: number): Promise<ApiResponse<Question>>;\n getTopScoredQuestions(page?: number): Promise<ApiResponse<Question>>;\n getUnansweredQuestions(page?: number): Promise<ApiResponse<Question>>;\n}\n\nexport const createStackOverflowApi = (\n discoveryApi: DiscoveryApi,\n fetchApi: FetchApi,\n): StackOverflowAPI => {\n const getBaseUrl = async () => discoveryApi.getBaseUrl('stack-overflow-teams');\n\n const requestAPI = async <T>(\n endpoint: string,\n method: 'GET' | 'POST' = 'GET',\n body?: Record<string, unknown>,\n params?: string[],\n ): Promise<T> => {\n const baseUrl = await getBaseUrl();\n const queryString = params ? `?${params.join('&')}` : '';\n const url = `${baseUrl}/${endpoint}${queryString}`;\n \n const response = await fetchApi.fetch(url, {\n method,\n credentials: 'include',\n headers: { 'Content-Type': 'application/json' },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const errorResponse = await response.json();\n throw new Error(errorResponse.error || `Request failed: ${response.statusText}`);\n }\n\n return response.json();\n };\n\n const buildQuestionParams = (filter?: QuestionsFilter): string[] => {\n const params: string[] = [];\n \n if (filter?.sort) {\n params.push(`sort=${filter.sort}`);\n }\n \n if (filter?.order) {\n params.push(`order=${filter.order}`);\n }\n \n if (filter?.isAnswered !== undefined) {\n params.push(`isAnswered=${filter.isAnswered}`);\n }\n \n if (filter?.page !== undefined) {\n params.push(`page=${filter.page}`);\n }\n \n if (filter?.pageSize !== undefined) {\n params.push(`pageSize=${filter.pageSize}`);\n }\n \n return params;\n };\n\n return {\n search: (query: string, page?: number) => {\n const body: { query: string; page?: number } = { query };\n if (page !== undefined) {\n body.page = page;\n }\n return requestAPI<any>('search', 'POST', body);\n },\n getQuestions: (filter?: QuestionsFilter) => {\n const params = buildQuestionParams(filter);\n return requestAPI<ApiResponse<Question>>('questions', 'GET', undefined, params.length > 0 ? params : undefined);\n },\n getTags: (search?: string) => {\n const params = search ? [`search=${encodeURIComponent(search)}`] : undefined;\n return requestAPI<ApiResponse<Tag>>('tags', 'GET', undefined, params);\n },\n getUsers: () => requestAPI<ApiResponse<User>>('users'),\n getMe: () => requestAPI<User>('me'),\n getBaseUrl: async () => {\n const response = await requestAPI<BaseUrlResponse>('baseurl');\n return response.SOInstance;\n },\n getTeamName: async () => {\n const response = await requestAPI<BaseUrlResponse>('baseurl')\n return response.teamName\n },\n postQuestion: (title: string, body: string, tags: string[]) =>\n requestAPI<Question>('questions', 'POST', { title, body, tags }),\n startAuth: async () => {\n const data = await requestAPI<{ authUrl: string }>('auth/start');\n return data.authUrl;\n },\n completeAuth: async (code: string, state: string) => {\n await requestAPI('callback', 'GET', undefined, [\n `code=${encodeURIComponent(code)}`,\n `state=${encodeURIComponent(state)}`,\n ]);\n },\n getAuthStatus: async (): Promise<boolean> => {\n try {\n await requestAPI('authStatus');\n return true;\n } catch {\n return false;\n }\n },\n logout: async (): Promise<boolean> => {\n try {\n await requestAPI('logout', 'POST');\n return true;\n } catch {\n return false;\n }\n },\n submitAccessToken: async (token: string): Promise<boolean> => {\n try {\n await requestAPI('auth/token', 'POST', { accessToken: token });\n return true;\n } catch {\n return false;\n }\n },\n\n // Convenience methods for common filtering scenarios\n getActiveQuestions: (page?: number) => {\n const params = buildQuestionParams({ sort: 'activity', order: 'desc', page });\n return requestAPI<ApiResponse<Question>>('questions', 'GET', undefined, params);\n },\n\n getNewestQuestions: (page?: number) => {\n const params = buildQuestionParams({ sort: 'creation', order: 'desc', page });\n return requestAPI<ApiResponse<Question>>('questions', 'GET', undefined, params);\n },\n\n getTopScoredQuestions: (page?: number) => {\n const params = buildQuestionParams({ sort: 'score', order: 'desc', page });\n return requestAPI<ApiResponse<Question>>('questions', 'GET', undefined, params);\n },\n\n getUnansweredQuestions: (page?: number) => {\n const params = buildQuestionParams({ isAnswered: false, sort: 'creation', order: 'desc', page });\n return requestAPI<ApiResponse<Question>>('questions', 'GET', undefined, params);\n },\n };\n};"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useApi } from '@backstage/core-plugin-api';
3
+ import { stackoverflowteamsApiRef } from '../../api/StackOverflowAPI.esm.js';
4
+ import { useState, useEffect } from 'react';
5
+ import { Box, CircularProgress, Typography, Card, IconButton, CardContent, Avatar, Chip, Link } from '@mui/material';
6
+ import { LogoutIcon } from '../../icons/LogoutIcon.esm.js';
7
+
8
+ const StackOverflowMe = () => {
9
+ const stackOverflowTeamsApi = useApi(stackoverflowteamsApiRef);
10
+ const logout = async () => {
11
+ try {
12
+ const success = await stackOverflowTeamsApi.logout();
13
+ if (success) {
14
+ window.location.reload();
15
+ } else {
16
+ throw new Error("Logout failed.");
17
+ }
18
+ } catch (error2) {
19
+ throw new Error("Error during logout:", error2);
20
+ }
21
+ };
22
+ const [userData, setUserData] = useState(null);
23
+ const [loading, setLoading] = useState(true);
24
+ const [error, setError] = useState(null);
25
+ useEffect(() => {
26
+ const fetchMe = async () => {
27
+ try {
28
+ const data = await stackOverflowTeamsApi.getMe();
29
+ setUserData(data);
30
+ } catch (err) {
31
+ setError("Failed to load user data");
32
+ } finally {
33
+ setLoading(false);
34
+ }
35
+ };
36
+ fetchMe();
37
+ }, [stackOverflowTeamsApi]);
38
+ if (loading) {
39
+ return /* @__PURE__ */ jsx(
40
+ Box,
41
+ {
42
+ display: "flex",
43
+ justifyContent: "center",
44
+ alignItems: "center",
45
+ width: "100%",
46
+ children: /* @__PURE__ */ jsx(CircularProgress, { color: "primary" })
47
+ }
48
+ );
49
+ }
50
+ if (error) {
51
+ return /* @__PURE__ */ jsx(
52
+ Box,
53
+ {
54
+ display: "flex",
55
+ justifyContent: "center",
56
+ alignItems: "center",
57
+ width: "100%",
58
+ children: /* @__PURE__ */ jsx(Typography, { color: "error", children: error })
59
+ }
60
+ );
61
+ }
62
+ if (!userData) return null;
63
+ return /* @__PURE__ */ jsx(
64
+ Box,
65
+ {
66
+ display: "flex",
67
+ justifyContent: "center",
68
+ alignItems: "center",
69
+ width: "100%",
70
+ children: /* @__PURE__ */ jsxs(
71
+ Card,
72
+ {
73
+ variant: "outlined",
74
+ sx: {
75
+ p: 3,
76
+ position: "relative",
77
+ boxShadow: 3
78
+ },
79
+ children: [
80
+ /* @__PURE__ */ jsx(Box, { sx: { position: "absolute", top: 8, right: 8 }, children: /* @__PURE__ */ jsx(
81
+ IconButton,
82
+ {
83
+ onClick: logout,
84
+ children: /* @__PURE__ */ jsx(LogoutIcon, {})
85
+ }
86
+ ) }),
87
+ /* @__PURE__ */ jsxs(CardContent, { sx: { textAlign: "center" }, children: [
88
+ /* @__PURE__ */ jsx(Avatar, { src: userData.avatarUrl, sx: { mx: "auto", mb: 2 } }),
89
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", fontWeight: "bold", gutterBottom: true, children: userData.name }),
90
+ /* @__PURE__ */ jsxs(Box, { display: "flex", justifyContent: "center", gap: 1, mb: 1, children: [
91
+ /* @__PURE__ */ jsx(
92
+ Chip,
93
+ {
94
+ label: `Reputation: ${userData.reputation}`,
95
+ size: "small",
96
+ color: "primary"
97
+ }
98
+ ),
99
+ /* @__PURE__ */ jsx(Chip, { label: userData.role, size: "small", variant: "outlined" })
100
+ ] }),
101
+ userData.jobTitle && /* @__PURE__ */ jsxs(Typography, { variant: "body2", fontWeight: "500", mt: 1, children: [
102
+ "Position: ",
103
+ userData.jobTitle
104
+ ] }),
105
+ /* @__PURE__ */ jsx(
106
+ Link,
107
+ {
108
+ href: userData.webUrl,
109
+ target: "_blank",
110
+ rel: "noopener",
111
+ color: "primary",
112
+ sx: { display: "block", mt: 2, fontWeight: "bold" },
113
+ children: "View Profile"
114
+ }
115
+ )
116
+ ] })
117
+ ]
118
+ }
119
+ )
120
+ }
121
+ );
122
+ };
123
+
124
+ export { StackOverflowMe };
125
+ //# sourceMappingURL=StackOverflowMe.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StackOverflowMe.esm.js","sources":["../../../src/components/StackOverflow/StackOverflowMe.tsx"],"sourcesContent":["import { useApi } from '@backstage/core-plugin-api';\nimport { stackoverflowteamsApiRef, User } from '../../api';\nimport { useEffect, useState } from 'react';\n// eslint-disable-next-line no-restricted-imports\nimport {\n Box,\n Avatar,\n Typography,\n Card,\n CardContent,\n Link,\n CircularProgress,\n Chip,\n IconButton,\n} from '@mui/material';\nimport { LogoutIcon } from '../../icons';\n\nexport const StackOverflowMe = () => {\n const stackOverflowTeamsApi = useApi(stackoverflowteamsApiRef);\n const logout = async () => {\n try {\n const success = await stackOverflowTeamsApi.logout();\n if (success) {\n window.location.reload();\n } else {\n throw new Error('Logout failed.');\n }\n } catch (error:any) {\n throw new Error('Error during logout:', error);\n }\n };\n\n const [userData, setUserData] = useState<User | null>(null);\n const [loading, setLoading] = useState<Boolean>(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const fetchMe = async () => {\n try {\n const data = await stackOverflowTeamsApi.getMe();\n setUserData(data);\n } catch (err) {\n setError('Failed to load user data');\n } finally {\n setLoading(false);\n }\n };\n\n fetchMe();\n }, [stackOverflowTeamsApi]);\n\n if (loading) {\n return (\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n width=\"100%\"\n >\n <CircularProgress color=\"primary\" />\n </Box>\n );\n }\n\n if (error) {\n return (\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n width=\"100%\"\n >\n <Typography color=\"error\">{error}</Typography>\n </Box>\n );\n }\n\n if (!userData) return null;\n\n return (\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n width=\"100%\"\n >\n <Card\n variant=\"outlined\"\n sx={{\n p: 3,\n position: 'relative',\n boxShadow: 3,\n }}\n >\n {/* Logout Button */}\n <Box sx={{ position: 'absolute', top: 8, right: 8 }}>\n <IconButton\n \n onClick={logout}\n >\n <LogoutIcon />\n </IconButton>\n </Box>\n <CardContent sx={{ textAlign: 'center' }}>\n {/* Avatar */}\n <Avatar src={userData.avatarUrl} sx={{ mx: 'auto', mb: 2 }} />\n\n {/* User Details */}\n <Typography variant=\"h6\" fontWeight=\"bold\" gutterBottom>\n {userData.name}\n </Typography>\n\n <Box display=\"flex\" justifyContent=\"center\" gap={1} mb={1}>\n <Chip\n label={`Reputation: ${userData.reputation}`}\n size=\"small\"\n color=\"primary\"\n />\n <Chip label={userData.role} size=\"small\" variant=\"outlined\" />\n </Box>\n\n {userData.jobTitle && (\n <Typography variant=\"body2\" fontWeight=\"500\" mt={1}>\n Position: {userData.jobTitle}\n </Typography>\n )}\n\n {/* Profile Link */}\n <Link\n href={userData.webUrl}\n target=\"_blank\"\n rel=\"noopener\"\n color=\"primary\"\n sx={{ display: 'block', mt: 2, fontWeight: 'bold' }}\n >\n View Profile\n </Link>\n </CardContent>\n </Card>\n </Box>\n );\n};\n"],"names":["error"],"mappings":"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"}