@buoy-gg/impersonate 1.0.3-beta.0

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 (95) hide show
  1. package/LICENSE +58 -0
  2. package/lib/commonjs/impersonate/components/DataNukeSettings.js +715 -0
  3. package/lib/commonjs/impersonate/components/ImpersonateBanner.js +217 -0
  4. package/lib/commonjs/impersonate/components/ImpersonateHistoryList.js +173 -0
  5. package/lib/commonjs/impersonate/components/ImpersonateModal.js +304 -0
  6. package/lib/commonjs/impersonate/components/ImpersonateStatusBar.js +130 -0
  7. package/lib/commonjs/impersonate/components/UserAvatar.js +146 -0
  8. package/lib/commonjs/impersonate/components/UserCard.js +200 -0
  9. package/lib/commonjs/impersonate/components/UserSearchView.js +227 -0
  10. package/lib/commonjs/impersonate/components/index.js +85 -0
  11. package/lib/commonjs/impersonate/hooks/index.js +64 -0
  12. package/lib/commonjs/impersonate/hooks/useAutoClearAsyncStorage.js +144 -0
  13. package/lib/commonjs/impersonate/hooks/useAutoClearReactQuery.js +155 -0
  14. package/lib/commonjs/impersonate/hooks/useAutoClearRedux.js +188 -0
  15. package/lib/commonjs/impersonate/hooks/useImpersonate.js +215 -0
  16. package/lib/commonjs/impersonate/hooks/useImpersonateHistory.js +56 -0
  17. package/lib/commonjs/impersonate/index.js +49 -0
  18. package/lib/commonjs/impersonate/types/index.js +16 -0
  19. package/lib/commonjs/impersonate/types/types.js +1 -0
  20. package/lib/commonjs/impersonate/utils/impersonateListener.js +280 -0
  21. package/lib/commonjs/impersonate/utils/impersonateStore.js +607 -0
  22. package/lib/commonjs/impersonate/utils/index.js +49 -0
  23. package/lib/commonjs/index.js +118 -0
  24. package/lib/commonjs/package.json +1 -0
  25. package/lib/commonjs/preset.js +214 -0
  26. package/lib/module/impersonate/components/DataNukeSettings.js +710 -0
  27. package/lib/module/impersonate/components/ImpersonateBanner.js +211 -0
  28. package/lib/module/impersonate/components/ImpersonateHistoryList.js +168 -0
  29. package/lib/module/impersonate/components/ImpersonateModal.js +300 -0
  30. package/lib/module/impersonate/components/ImpersonateStatusBar.js +125 -0
  31. package/lib/module/impersonate/components/UserAvatar.js +140 -0
  32. package/lib/module/impersonate/components/UserCard.js +195 -0
  33. package/lib/module/impersonate/components/UserSearchView.js +222 -0
  34. package/lib/module/impersonate/components/index.js +11 -0
  35. package/lib/module/impersonate/hooks/index.js +7 -0
  36. package/lib/module/impersonate/hooks/useAutoClearAsyncStorage.js +140 -0
  37. package/lib/module/impersonate/hooks/useAutoClearReactQuery.js +151 -0
  38. package/lib/module/impersonate/hooks/useAutoClearRedux.js +183 -0
  39. package/lib/module/impersonate/hooks/useImpersonate.js +212 -0
  40. package/lib/module/impersonate/hooks/useImpersonateHistory.js +52 -0
  41. package/lib/module/impersonate/index.js +13 -0
  42. package/lib/module/impersonate/types/index.js +3 -0
  43. package/lib/module/impersonate/types/types.js +1 -0
  44. package/lib/module/impersonate/utils/impersonateListener.js +271 -0
  45. package/lib/module/impersonate/utils/impersonateStore.js +604 -0
  46. package/lib/module/impersonate/utils/index.js +4 -0
  47. package/lib/module/index.js +103 -0
  48. package/lib/module/preset.js +209 -0
  49. package/lib/typescript/impersonate/components/DataNukeSettings.d.ts +37 -0
  50. package/lib/typescript/impersonate/components/DataNukeSettings.d.ts.map +1 -0
  51. package/lib/typescript/impersonate/components/ImpersonateBanner.d.ts +40 -0
  52. package/lib/typescript/impersonate/components/ImpersonateBanner.d.ts.map +1 -0
  53. package/lib/typescript/impersonate/components/ImpersonateHistoryList.d.ts +24 -0
  54. package/lib/typescript/impersonate/components/ImpersonateHistoryList.d.ts.map +1 -0
  55. package/lib/typescript/impersonate/components/ImpersonateModal.d.ts +10 -0
  56. package/lib/typescript/impersonate/components/ImpersonateModal.d.ts.map +1 -0
  57. package/lib/typescript/impersonate/components/ImpersonateStatusBar.d.ts +15 -0
  58. package/lib/typescript/impersonate/components/ImpersonateStatusBar.d.ts.map +1 -0
  59. package/lib/typescript/impersonate/components/UserAvatar.d.ts +32 -0
  60. package/lib/typescript/impersonate/components/UserAvatar.d.ts.map +1 -0
  61. package/lib/typescript/impersonate/components/UserCard.d.ts +28 -0
  62. package/lib/typescript/impersonate/components/UserCard.d.ts.map +1 -0
  63. package/lib/typescript/impersonate/components/UserSearchView.d.ts +31 -0
  64. package/lib/typescript/impersonate/components/UserSearchView.d.ts.map +1 -0
  65. package/lib/typescript/impersonate/components/index.d.ts +16 -0
  66. package/lib/typescript/impersonate/components/index.d.ts.map +1 -0
  67. package/lib/typescript/impersonate/hooks/index.d.ts +11 -0
  68. package/lib/typescript/impersonate/hooks/index.d.ts.map +1 -0
  69. package/lib/typescript/impersonate/hooks/useAutoClearAsyncStorage.d.ts +48 -0
  70. package/lib/typescript/impersonate/hooks/useAutoClearAsyncStorage.d.ts.map +1 -0
  71. package/lib/typescript/impersonate/hooks/useAutoClearReactQuery.d.ts +48 -0
  72. package/lib/typescript/impersonate/hooks/useAutoClearReactQuery.d.ts.map +1 -0
  73. package/lib/typescript/impersonate/hooks/useAutoClearRedux.d.ts +78 -0
  74. package/lib/typescript/impersonate/hooks/useAutoClearRedux.d.ts.map +1 -0
  75. package/lib/typescript/impersonate/hooks/useImpersonate.d.ts +76 -0
  76. package/lib/typescript/impersonate/hooks/useImpersonate.d.ts.map +1 -0
  77. package/lib/typescript/impersonate/hooks/useImpersonateHistory.d.ts +43 -0
  78. package/lib/typescript/impersonate/hooks/useImpersonateHistory.d.ts.map +1 -0
  79. package/lib/typescript/impersonate/index.d.ts +5 -0
  80. package/lib/typescript/impersonate/index.d.ts.map +1 -0
  81. package/lib/typescript/impersonate/types/index.d.ts +2 -0
  82. package/lib/typescript/impersonate/types/index.d.ts.map +1 -0
  83. package/lib/typescript/impersonate/types/types.d.ts +177 -0
  84. package/lib/typescript/impersonate/types/types.d.ts.map +1 -0
  85. package/lib/typescript/impersonate/utils/impersonateListener.d.ts +115 -0
  86. package/lib/typescript/impersonate/utils/impersonateListener.d.ts.map +1 -0
  87. package/lib/typescript/impersonate/utils/impersonateStore.d.ts +151 -0
  88. package/lib/typescript/impersonate/utils/impersonateStore.d.ts.map +1 -0
  89. package/lib/typescript/impersonate/utils/index.d.ts +3 -0
  90. package/lib/typescript/impersonate/utils/index.d.ts.map +1 -0
  91. package/lib/typescript/index.d.ts +80 -0
  92. package/lib/typescript/index.d.ts.map +1 -0
  93. package/lib/typescript/preset.d.ts +71 -0
  94. package/lib/typescript/preset.d.ts.map +1 -0
  95. package/package.json +78 -0
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ImpersonateStatusBar = ImpersonateStatusBar;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _sharedUi = require("@buoy-gg/shared-ui");
10
+ var _UserAvatar = require("./UserAvatar");
11
+ var _jsxRuntime = require("react/jsx-runtime");
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
+ /**
14
+ * ImpersonateStatusBar Component
15
+ *
16
+ * Shows the current impersonation status with user avatar, info and stop button.
17
+ * Displays at the top of the modal when impersonation is active.
18
+ */
19
+
20
+ function ImpersonateStatusBar({
21
+ user,
22
+ onStopImpersonation
23
+ }) {
24
+ const displayName = user.displayName || user.email || user.id;
25
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
26
+ style: styles.container,
27
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
28
+ style: styles.userSection,
29
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_UserAvatar.UserAvatar, {
30
+ userId: user.id,
31
+ name: displayName,
32
+ size: "small",
33
+ showActiveIndicator: false
34
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
35
+ style: styles.userInfo,
36
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
37
+ style: styles.userName,
38
+ numberOfLines: 1,
39
+ children: displayName
40
+ })
41
+ })]
42
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
43
+ style: styles.statusPill,
44
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
45
+ style: styles.pulseDot
46
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
47
+ style: styles.statusText,
48
+ children: "Active"
49
+ })]
50
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
51
+ style: styles.stopButton,
52
+ onPress: onStopImpersonation,
53
+ activeOpacity: 0.7,
54
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
55
+ size: 12,
56
+ color: _sharedUi.buoyColors.error
57
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
58
+ style: styles.stopButtonText,
59
+ children: "Stop"
60
+ })]
61
+ })]
62
+ });
63
+ }
64
+ const styles = _reactNative.StyleSheet.create({
65
+ container: {
66
+ flexDirection: "row",
67
+ alignItems: "center",
68
+ justifyContent: "space-between",
69
+ paddingVertical: 10,
70
+ paddingHorizontal: 16,
71
+ backgroundColor: _sharedUi.buoyColors.success + "10",
72
+ borderBottomWidth: 1,
73
+ borderBottomColor: _sharedUi.buoyColors.success + "25",
74
+ gap: 12
75
+ },
76
+ userSection: {
77
+ flexDirection: "row",
78
+ alignItems: "center",
79
+ flex: 1,
80
+ gap: 10,
81
+ minWidth: 0
82
+ },
83
+ userInfo: {
84
+ flex: 1,
85
+ minWidth: 0
86
+ },
87
+ userName: {
88
+ fontSize: 14,
89
+ fontWeight: "600",
90
+ color: _sharedUi.buoyColors.text
91
+ },
92
+ statusPill: {
93
+ flexDirection: "row",
94
+ alignItems: "center",
95
+ gap: 6,
96
+ backgroundColor: _sharedUi.buoyColors.success + "20",
97
+ paddingHorizontal: 10,
98
+ paddingVertical: 5,
99
+ borderRadius: 12
100
+ },
101
+ pulseDot: {
102
+ width: 6,
103
+ height: 6,
104
+ borderRadius: 3,
105
+ backgroundColor: _sharedUi.buoyColors.success
106
+ },
107
+ statusText: {
108
+ fontSize: 11,
109
+ fontWeight: "600",
110
+ color: _sharedUi.buoyColors.success,
111
+ textTransform: "uppercase",
112
+ letterSpacing: 0.5
113
+ },
114
+ stopButton: {
115
+ flexDirection: "row",
116
+ alignItems: "center",
117
+ gap: 4,
118
+ paddingHorizontal: 12,
119
+ paddingVertical: 6,
120
+ backgroundColor: _sharedUi.buoyColors.error + "15",
121
+ borderRadius: 6,
122
+ borderWidth: 1,
123
+ borderColor: _sharedUi.buoyColors.error + "30"
124
+ },
125
+ stopButtonText: {
126
+ fontSize: 12,
127
+ fontWeight: "600",
128
+ color: _sharedUi.buoyColors.error
129
+ }
130
+ });
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.AVATAR_COLORS = void 0;
7
+ exports.UserAvatar = UserAvatar;
8
+ exports.getAvatarColor = getAvatarColor;
9
+ exports.getInitials = getInitials;
10
+ var _react = _interopRequireWildcard(require("react"));
11
+ var _reactNative = require("react-native");
12
+ var _sharedUi = require("@buoy-gg/shared-ui");
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
15
+ /**
16
+ * UserAvatar Component
17
+ *
18
+ * Displays a user avatar with initials and deterministic color.
19
+ * Supports size variants and active indicator.
20
+ */
21
+
22
+ // Avatar background colors - deterministic based on user ID
23
+ const AVATAR_COLORS = exports.AVATAR_COLORS = ["#6366F1",
24
+ // Indigo
25
+ "#8B5CF6",
26
+ // Purple
27
+ "#EC4899",
28
+ // Pink
29
+ "#F43F5E",
30
+ // Rose
31
+ "#F97316",
32
+ // Orange
33
+ "#EAB308",
34
+ // Yellow
35
+ "#22C55E",
36
+ // Green
37
+ "#14B8A6",
38
+ // Teal
39
+ "#06B6D4",
40
+ // Cyan
41
+ "#3B82F6" // Blue
42
+ ];
43
+ const SIZES = {
44
+ small: {
45
+ container: 24,
46
+ font: 10,
47
+ indicator: 8
48
+ },
49
+ medium: {
50
+ container: 36,
51
+ font: 14,
52
+ indicator: 10
53
+ },
54
+ large: {
55
+ container: 44,
56
+ font: 16,
57
+ indicator: 12
58
+ }
59
+ };
60
+ /**
61
+ * Get initials from a name or email
62
+ */
63
+ function getInitials(name) {
64
+ if (!name) return "?";
65
+
66
+ // If it's an email, use first letter before @
67
+ if (name.includes("@")) {
68
+ return name.charAt(0).toUpperCase();
69
+ }
70
+
71
+ // Split by spaces and get first letter of first two words
72
+ const parts = name.trim().split(/\s+/);
73
+ if (parts.length === 1) {
74
+ return parts[0].charAt(0).toUpperCase();
75
+ }
76
+ return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase();
77
+ }
78
+
79
+ /**
80
+ * Get deterministic color based on user ID
81
+ */
82
+ function getAvatarColor(userId) {
83
+ let hash = 0;
84
+ for (let i = 0; i < userId.length; i++) {
85
+ hash = userId.charCodeAt(i) + ((hash << 5) - hash);
86
+ }
87
+ return AVATAR_COLORS[Math.abs(hash) % AVATAR_COLORS.length];
88
+ }
89
+ function UserAvatar({
90
+ userId,
91
+ name,
92
+ size = "medium",
93
+ showActiveIndicator = false,
94
+ backgroundColor
95
+ }) {
96
+ const sizeConfig = SIZES[size];
97
+ const avatarColor = (0, _react.useMemo)(() => backgroundColor ?? getAvatarColor(userId), [userId, backgroundColor]);
98
+ const initials = (0, _react.useMemo)(() => getInitials(name), [name]);
99
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
100
+ style: styles.wrapper,
101
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
102
+ style: [styles.container, {
103
+ width: sizeConfig.container,
104
+ height: sizeConfig.container,
105
+ borderRadius: sizeConfig.container / 2,
106
+ backgroundColor: avatarColor
107
+ }],
108
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
109
+ style: [styles.initials, {
110
+ fontSize: sizeConfig.font
111
+ }],
112
+ children: initials
113
+ })
114
+ }), showActiveIndicator && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
115
+ style: [styles.indicator, {
116
+ width: sizeConfig.indicator,
117
+ height: sizeConfig.indicator,
118
+ borderRadius: sizeConfig.indicator / 2,
119
+ right: -1,
120
+ bottom: -1
121
+ }]
122
+ })]
123
+ });
124
+ }
125
+ const styles = _reactNative.StyleSheet.create({
126
+ wrapper: {
127
+ position: "relative"
128
+ },
129
+ container: {
130
+ alignItems: "center",
131
+ justifyContent: "center"
132
+ },
133
+ initials: {
134
+ color: "#FFFFFF",
135
+ fontWeight: "600",
136
+ letterSpacing: 0.5
137
+ },
138
+ indicator: {
139
+ position: "absolute",
140
+ backgroundColor: _sharedUi.buoyColors.success,
141
+ borderWidth: 2,
142
+ borderColor: _sharedUi.buoyColors.card
143
+ }
144
+ });
145
+
146
+ // Export helper functions for reuse
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.UserCard = UserCard;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _sharedUi = require("@buoy-gg/shared-ui");
10
+ var _UserAvatar = require("./UserAvatar");
11
+ var _jsxRuntime = require("react/jsx-runtime");
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
+ /**
14
+ * UserCard Component
15
+ *
16
+ * Polished user card for search results and history.
17
+ * Features avatar, clean typography hierarchy, and contextual actions.
18
+ */
19
+
20
+ function UserCard({
21
+ user,
22
+ isActive = false,
23
+ onPress,
24
+ onStop,
25
+ onRemove,
26
+ showRemoveButton = false,
27
+ lastUsedTime,
28
+ variant = "default"
29
+ }) {
30
+ const displayName = user.displayName || user.email || user.id;
31
+ const showEmail = user.email && user.displayName;
32
+ const role = typeof user.metadata?.role === "string" ? user.metadata.role : null;
33
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
34
+ style: [styles.container, isActive && styles.activeContainer, variant === "compact" && styles.compactContainer],
35
+ onPress: onPress,
36
+ disabled: isActive,
37
+ activeOpacity: 0.7,
38
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
39
+ style: styles.avatarSection,
40
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_UserAvatar.UserAvatar, {
41
+ userId: user.id,
42
+ name: displayName,
43
+ size: variant === "compact" ? "small" : "medium",
44
+ showActiveIndicator: isActive
45
+ })
46
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
47
+ style: styles.content,
48
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
49
+ style: styles.nameRow,
50
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
51
+ style: [styles.name, isActive && styles.activeName],
52
+ numberOfLines: 1,
53
+ children: displayName
54
+ }), role && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
55
+ style: styles.roleBadge,
56
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
57
+ style: styles.roleBadgeText,
58
+ children: role.toUpperCase()
59
+ })
60
+ })]
61
+ }), showEmail && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
62
+ style: styles.email,
63
+ numberOfLines: 1,
64
+ children: user.email
65
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
66
+ style: styles.metadataRow,
67
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
68
+ style: styles.userId,
69
+ children: ["ID: ", user.id]
70
+ })
71
+ })]
72
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
73
+ style: styles.actions,
74
+ children: [isActive ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PowerToggleButton, {
75
+ isEnabled: true,
76
+ onToggle: onStop || (() => {}),
77
+ accessibilityLabel: "Stop impersonation"
78
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
79
+ style: styles.actionButton,
80
+ onPress: onPress,
81
+ activeOpacity: 0.7,
82
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Play, {
83
+ size: 14,
84
+ color: "#FFFFFF"
85
+ })
86
+ }), showRemoveButton && onRemove && !isActive && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
87
+ style: styles.removeButton,
88
+ onPress: onRemove,
89
+ activeOpacity: 0.7,
90
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
91
+ size: 12,
92
+ color: _sharedUi.buoyColors.textMuted
93
+ })
94
+ })]
95
+ }), lastUsedTime && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
96
+ style: styles.lastUsed,
97
+ children: lastUsedTime
98
+ })]
99
+ });
100
+ }
101
+ const styles = _reactNative.StyleSheet.create({
102
+ container: {
103
+ flexDirection: "row",
104
+ alignItems: "center",
105
+ backgroundColor: _sharedUi.buoyColors.card,
106
+ borderRadius: 10,
107
+ borderWidth: 1,
108
+ borderColor: _sharedUi.buoyColors.border,
109
+ padding: 12,
110
+ gap: 12
111
+ },
112
+ activeContainer: {
113
+ backgroundColor: _sharedUi.buoyColors.success + "10",
114
+ borderColor: _sharedUi.buoyColors.success + "40"
115
+ },
116
+ compactContainer: {
117
+ padding: 10,
118
+ gap: 10
119
+ },
120
+ avatarSection: {
121
+ flexShrink: 0
122
+ },
123
+ content: {
124
+ flex: 1,
125
+ minWidth: 0
126
+ },
127
+ nameRow: {
128
+ flexDirection: "row",
129
+ alignItems: "center",
130
+ gap: 8,
131
+ marginBottom: 2
132
+ },
133
+ name: {
134
+ fontSize: 15,
135
+ fontWeight: "600",
136
+ color: _sharedUi.buoyColors.text,
137
+ flexShrink: 1
138
+ },
139
+ activeName: {
140
+ color: _sharedUi.buoyColors.success
141
+ },
142
+ roleBadge: {
143
+ backgroundColor: _sharedUi.buoyColors.hover,
144
+ paddingHorizontal: 6,
145
+ paddingVertical: 2,
146
+ borderRadius: 4
147
+ },
148
+ roleBadgeText: {
149
+ fontSize: 9,
150
+ fontWeight: "700",
151
+ color: _sharedUi.buoyColors.textMuted,
152
+ letterSpacing: 0.5
153
+ },
154
+ email: {
155
+ fontSize: 13,
156
+ color: _sharedUi.buoyColors.textSecondary,
157
+ marginBottom: 4
158
+ },
159
+ metadataRow: {
160
+ flexDirection: "row",
161
+ alignItems: "center",
162
+ gap: 4
163
+ },
164
+ userId: {
165
+ fontSize: 11,
166
+ color: _sharedUi.buoyColors.textMuted,
167
+ fontFamily: "monospace"
168
+ },
169
+ lastUsed: {
170
+ position: "absolute",
171
+ bottom: 8,
172
+ right: 10,
173
+ fontSize: 10,
174
+ color: _sharedUi.buoyColors.textMuted
175
+ },
176
+ actions: {
177
+ flexDirection: "row",
178
+ alignItems: "center",
179
+ gap: 8,
180
+ flexShrink: 0
181
+ },
182
+ actionButton: {
183
+ width: 36,
184
+ height: 36,
185
+ borderRadius: 8,
186
+ backgroundColor: _sharedUi.buoyColors.primary,
187
+ alignItems: "center",
188
+ justifyContent: "center"
189
+ },
190
+ removeButton: {
191
+ width: 28,
192
+ height: 28,
193
+ borderRadius: 6,
194
+ backgroundColor: _sharedUi.buoyColors.hover,
195
+ borderWidth: 1,
196
+ borderColor: _sharedUi.buoyColors.border,
197
+ alignItems: "center",
198
+ justifyContent: "center"
199
+ }
200
+ });
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.UserSearchView = UserSearchView;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _sharedUi = require("@buoy-gg/shared-ui");
10
+ var _UserCard = require("./UserCard");
11
+ var _jsxRuntime = require("react/jsx-runtime");
12
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
+ /**
14
+ * UserSearchView Component
15
+ *
16
+ * Displays search results for user impersonation.
17
+ * Search input is handled by the parent modal's header.
18
+ * Uses polished UserCard component for results.
19
+ */
20
+
21
+ function UserSearchView({
22
+ currentUser,
23
+ searchQuery,
24
+ searchResults,
25
+ isSearching,
26
+ searchError,
27
+ onSelectUser,
28
+ onStopImpersonation,
29
+ searchAvailable = true
30
+ }) {
31
+ const renderUserItem = (0, _react.useCallback)(({
32
+ item
33
+ }) => {
34
+ const isCurrentUser = currentUser?.id === item.id;
35
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_UserCard.UserCard, {
36
+ user: item,
37
+ isActive: isCurrentUser,
38
+ onPress: () => !isCurrentUser && onSelectUser(item),
39
+ onStop: isCurrentUser ? onStopImpersonation : undefined
40
+ });
41
+ }, [currentUser, onSelectUser, onStopImpersonation]);
42
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
43
+ style: styles.container,
44
+ children: [!searchAvailable && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
45
+ style: styles.section,
46
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
47
+ style: styles.warningCard,
48
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AlertTriangle, {
49
+ size: 18,
50
+ color: _sharedUi.buoyColors.warning
51
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
52
+ style: styles.warningContent,
53
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
54
+ style: styles.warningTitle,
55
+ children: "Search Not Available"
56
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
57
+ style: styles.warningText,
58
+ children: "Configure the onSearchUsers callback to enable user search."
59
+ })]
60
+ })]
61
+ })
62
+ }), isSearching && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
63
+ style: styles.loadingContainer,
64
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
65
+ size: "small",
66
+ color: _sharedUi.buoyColors.primary
67
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
68
+ style: styles.loadingText,
69
+ children: "Searching users..."
70
+ })]
71
+ }), searchError && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
72
+ style: styles.section,
73
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
74
+ style: styles.errorCard,
75
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AlertTriangle, {
76
+ size: 16,
77
+ color: _sharedUi.buoyColors.error
78
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
79
+ style: styles.errorText,
80
+ children: searchError
81
+ })]
82
+ })
83
+ }), searchResults.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
84
+ style: styles.resultsSection,
85
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.SectionHeader, {
86
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Title, {
87
+ children: "Results"
88
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Badge, {
89
+ count: searchResults.length
90
+ })]
91
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
92
+ data: searchResults,
93
+ keyExtractor: item => item.id,
94
+ renderItem: renderUserItem,
95
+ ItemSeparatorComponent: () => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
96
+ style: styles.separator
97
+ }),
98
+ contentContainerStyle: styles.listContent,
99
+ showsVerticalScrollIndicator: false
100
+ })]
101
+ }), searchQuery && !isSearching && searchResults.length === 0 && !searchError && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
102
+ style: styles.emptyStateContainer,
103
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
104
+ style: styles.emptyStateIcon,
105
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Users, {
106
+ size: 28,
107
+ color: _sharedUi.buoyColors.textMuted
108
+ })
109
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
110
+ style: styles.emptyStateTitle,
111
+ children: "No users found"
112
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
113
+ style: styles.emptyStateDescription,
114
+ children: ["No results for \"", searchQuery, "\""]
115
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
116
+ style: styles.emptyStateHint,
117
+ children: "Try a different search term"
118
+ })]
119
+ }), !searchQuery && searchResults.length === 0 && !isSearching && searchAvailable && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EmptyState, {
120
+ title: "Search for users",
121
+ description: "Tap the search icon in the header to find users by email, name, or ID",
122
+ icon: _sharedUi.Search,
123
+ variant: "minimal"
124
+ })]
125
+ });
126
+ }
127
+ const styles = _reactNative.StyleSheet.create({
128
+ container: {
129
+ flex: 1
130
+ },
131
+ section: {
132
+ padding: 16,
133
+ paddingBottom: 8
134
+ },
135
+ loadingContainer: {
136
+ flexDirection: "row",
137
+ alignItems: "center",
138
+ justifyContent: "center",
139
+ gap: 10,
140
+ paddingVertical: 20
141
+ },
142
+ loadingText: {
143
+ fontSize: 13,
144
+ color: _sharedUi.buoyColors.textSecondary
145
+ },
146
+ resultsSection: {
147
+ flex: 1,
148
+ paddingHorizontal: 16
149
+ },
150
+ listContent: {
151
+ paddingBottom: 16
152
+ },
153
+ separator: {
154
+ height: 8
155
+ },
156
+ warningCard: {
157
+ flexDirection: "row",
158
+ alignItems: "flex-start",
159
+ gap: 12,
160
+ backgroundColor: _sharedUi.buoyColors.warning + "12",
161
+ borderRadius: 10,
162
+ borderWidth: 1,
163
+ borderColor: _sharedUi.buoyColors.warning + "25",
164
+ padding: 14
165
+ },
166
+ warningContent: {
167
+ flex: 1
168
+ },
169
+ warningTitle: {
170
+ fontSize: 14,
171
+ fontWeight: "600",
172
+ color: _sharedUi.buoyColors.warning,
173
+ marginBottom: 4
174
+ },
175
+ warningText: {
176
+ fontSize: 13,
177
+ color: _sharedUi.buoyColors.textSecondary,
178
+ lineHeight: 18
179
+ },
180
+ errorCard: {
181
+ flexDirection: "row",
182
+ alignItems: "center",
183
+ gap: 10,
184
+ backgroundColor: _sharedUi.buoyColors.error + "12",
185
+ borderRadius: 10,
186
+ borderWidth: 1,
187
+ borderColor: _sharedUi.buoyColors.error + "25",
188
+ padding: 12
189
+ },
190
+ errorText: {
191
+ flex: 1,
192
+ fontSize: 13,
193
+ color: _sharedUi.buoyColors.error
194
+ },
195
+ emptyStateContainer: {
196
+ flex: 1,
197
+ alignItems: "center",
198
+ justifyContent: "center",
199
+ paddingHorizontal: 32,
200
+ paddingVertical: 48
201
+ },
202
+ emptyStateIcon: {
203
+ width: 56,
204
+ height: 56,
205
+ borderRadius: 28,
206
+ backgroundColor: _sharedUi.buoyColors.hover,
207
+ alignItems: "center",
208
+ justifyContent: "center",
209
+ marginBottom: 16
210
+ },
211
+ emptyStateTitle: {
212
+ fontSize: 16,
213
+ fontWeight: "600",
214
+ color: _sharedUi.buoyColors.text,
215
+ marginBottom: 6
216
+ },
217
+ emptyStateDescription: {
218
+ fontSize: 14,
219
+ color: _sharedUi.buoyColors.textSecondary,
220
+ textAlign: "center",
221
+ marginBottom: 8
222
+ },
223
+ emptyStateHint: {
224
+ fontSize: 12,
225
+ color: _sharedUi.buoyColors.textMuted
226
+ }
227
+ });