@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.
- package/LICENSE +58 -0
- package/lib/commonjs/impersonate/components/DataNukeSettings.js +715 -0
- package/lib/commonjs/impersonate/components/ImpersonateBanner.js +217 -0
- package/lib/commonjs/impersonate/components/ImpersonateHistoryList.js +173 -0
- package/lib/commonjs/impersonate/components/ImpersonateModal.js +304 -0
- package/lib/commonjs/impersonate/components/ImpersonateStatusBar.js +130 -0
- package/lib/commonjs/impersonate/components/UserAvatar.js +146 -0
- package/lib/commonjs/impersonate/components/UserCard.js +200 -0
- package/lib/commonjs/impersonate/components/UserSearchView.js +227 -0
- package/lib/commonjs/impersonate/components/index.js +85 -0
- package/lib/commonjs/impersonate/hooks/index.js +64 -0
- package/lib/commonjs/impersonate/hooks/useAutoClearAsyncStorage.js +144 -0
- package/lib/commonjs/impersonate/hooks/useAutoClearReactQuery.js +155 -0
- package/lib/commonjs/impersonate/hooks/useAutoClearRedux.js +188 -0
- package/lib/commonjs/impersonate/hooks/useImpersonate.js +215 -0
- package/lib/commonjs/impersonate/hooks/useImpersonateHistory.js +56 -0
- package/lib/commonjs/impersonate/index.js +49 -0
- package/lib/commonjs/impersonate/types/index.js +16 -0
- package/lib/commonjs/impersonate/types/types.js +1 -0
- package/lib/commonjs/impersonate/utils/impersonateListener.js +280 -0
- package/lib/commonjs/impersonate/utils/impersonateStore.js +607 -0
- package/lib/commonjs/impersonate/utils/index.js +49 -0
- package/lib/commonjs/index.js +118 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/preset.js +214 -0
- package/lib/module/impersonate/components/DataNukeSettings.js +710 -0
- package/lib/module/impersonate/components/ImpersonateBanner.js +211 -0
- package/lib/module/impersonate/components/ImpersonateHistoryList.js +168 -0
- package/lib/module/impersonate/components/ImpersonateModal.js +300 -0
- package/lib/module/impersonate/components/ImpersonateStatusBar.js +125 -0
- package/lib/module/impersonate/components/UserAvatar.js +140 -0
- package/lib/module/impersonate/components/UserCard.js +195 -0
- package/lib/module/impersonate/components/UserSearchView.js +222 -0
- package/lib/module/impersonate/components/index.js +11 -0
- package/lib/module/impersonate/hooks/index.js +7 -0
- package/lib/module/impersonate/hooks/useAutoClearAsyncStorage.js +140 -0
- package/lib/module/impersonate/hooks/useAutoClearReactQuery.js +151 -0
- package/lib/module/impersonate/hooks/useAutoClearRedux.js +183 -0
- package/lib/module/impersonate/hooks/useImpersonate.js +212 -0
- package/lib/module/impersonate/hooks/useImpersonateHistory.js +52 -0
- package/lib/module/impersonate/index.js +13 -0
- package/lib/module/impersonate/types/index.js +3 -0
- package/lib/module/impersonate/types/types.js +1 -0
- package/lib/module/impersonate/utils/impersonateListener.js +271 -0
- package/lib/module/impersonate/utils/impersonateStore.js +604 -0
- package/lib/module/impersonate/utils/index.js +4 -0
- package/lib/module/index.js +103 -0
- package/lib/module/preset.js +209 -0
- package/lib/typescript/impersonate/components/DataNukeSettings.d.ts +37 -0
- package/lib/typescript/impersonate/components/DataNukeSettings.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/ImpersonateBanner.d.ts +40 -0
- package/lib/typescript/impersonate/components/ImpersonateBanner.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/ImpersonateHistoryList.d.ts +24 -0
- package/lib/typescript/impersonate/components/ImpersonateHistoryList.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/ImpersonateModal.d.ts +10 -0
- package/lib/typescript/impersonate/components/ImpersonateModal.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/ImpersonateStatusBar.d.ts +15 -0
- package/lib/typescript/impersonate/components/ImpersonateStatusBar.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/UserAvatar.d.ts +32 -0
- package/lib/typescript/impersonate/components/UserAvatar.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/UserCard.d.ts +28 -0
- package/lib/typescript/impersonate/components/UserCard.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/UserSearchView.d.ts +31 -0
- package/lib/typescript/impersonate/components/UserSearchView.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/index.d.ts +16 -0
- package/lib/typescript/impersonate/components/index.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/index.d.ts +11 -0
- package/lib/typescript/impersonate/hooks/index.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/useAutoClearAsyncStorage.d.ts +48 -0
- package/lib/typescript/impersonate/hooks/useAutoClearAsyncStorage.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/useAutoClearReactQuery.d.ts +48 -0
- package/lib/typescript/impersonate/hooks/useAutoClearReactQuery.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/useAutoClearRedux.d.ts +78 -0
- package/lib/typescript/impersonate/hooks/useAutoClearRedux.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/useImpersonate.d.ts +76 -0
- package/lib/typescript/impersonate/hooks/useImpersonate.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/useImpersonateHistory.d.ts +43 -0
- package/lib/typescript/impersonate/hooks/useImpersonateHistory.d.ts.map +1 -0
- package/lib/typescript/impersonate/index.d.ts +5 -0
- package/lib/typescript/impersonate/index.d.ts.map +1 -0
- package/lib/typescript/impersonate/types/index.d.ts +2 -0
- package/lib/typescript/impersonate/types/index.d.ts.map +1 -0
- package/lib/typescript/impersonate/types/types.d.ts +177 -0
- package/lib/typescript/impersonate/types/types.d.ts.map +1 -0
- package/lib/typescript/impersonate/utils/impersonateListener.d.ts +115 -0
- package/lib/typescript/impersonate/utils/impersonateListener.d.ts.map +1 -0
- package/lib/typescript/impersonate/utils/impersonateStore.d.ts +151 -0
- package/lib/typescript/impersonate/utils/impersonateStore.d.ts.map +1 -0
- package/lib/typescript/impersonate/utils/index.d.ts +3 -0
- package/lib/typescript/impersonate/utils/index.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +80 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts +71 -0
- package/lib/typescript/preset.d.ts.map +1 -0
- 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
|
+
});
|