@xipkg/calls-risehand 0.0.0 → 0.0.1
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/dist/index.mjs +7 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/index.mjs
CHANGED
|
@@ -16,7 +16,6 @@ var useRaisedHands = () => {
|
|
|
16
16
|
const handRaiseSoundVolume = useSoundEffectsStore((s) => s.handRaiseVolume);
|
|
17
17
|
const callId = navigation.getCallId();
|
|
18
18
|
const { room } = useRoom();
|
|
19
|
-
const { data: user } = useCalls().auth.useCurrentUser();
|
|
20
19
|
const { addRaisedHand, removeRaisedHand } = useCallStore();
|
|
21
20
|
const { updateParticipantMetadata, isPending } = useCalls().updateParticipantMetadata;
|
|
22
21
|
const isHandRaised = useMemo(() => {
|
|
@@ -32,19 +31,12 @@ var useRaisedHands = () => {
|
|
|
32
31
|
try {
|
|
33
32
|
await updateParticipantMetadata({
|
|
34
33
|
classroom_id: callId,
|
|
35
|
-
is_hand_raised: !isHandRaised
|
|
36
|
-
role: user?.defaultLayout
|
|
34
|
+
is_hand_raised: !isHandRaised
|
|
37
35
|
});
|
|
38
36
|
} catch (e) {
|
|
39
37
|
console.error("raise hand error", e);
|
|
40
38
|
}
|
|
41
|
-
}, [
|
|
42
|
-
room?.localParticipant,
|
|
43
|
-
callId,
|
|
44
|
-
updateParticipantMetadata,
|
|
45
|
-
isHandRaised,
|
|
46
|
-
user?.defaultLayout
|
|
47
|
-
]);
|
|
39
|
+
}, [room?.localParticipant, callId, updateParticipantMetadata, isHandRaised]);
|
|
48
40
|
useEffect(() => {
|
|
49
41
|
if (!room) return;
|
|
50
42
|
const syncParticipant = (participant) => {
|
|
@@ -118,18 +110,20 @@ var useHandFocus = () => {
|
|
|
118
110
|
}, [raisedHands, room, layoutContext]);
|
|
119
111
|
};
|
|
120
112
|
var RaiseHandButton = ({ className }) => {
|
|
121
|
-
const { toggleHand } = useRaisedHands();
|
|
122
|
-
const { isHandRaised } = useCallStore();
|
|
113
|
+
const { toggleHand, isHandRaised, isPending } = useRaisedHands();
|
|
123
114
|
return /* @__PURE__ */ jsx(
|
|
124
115
|
Button,
|
|
125
116
|
{
|
|
126
117
|
size: "icon",
|
|
127
|
-
variant: "
|
|
118
|
+
variant: "none",
|
|
128
119
|
onClick: toggleHand,
|
|
129
120
|
className: cn(
|
|
130
121
|
`relative m-0 h-10 w-10 rounded-lg p-0 ${isHandRaised ? "bg-brand-20 text-brand-100" : "hover:bg-gray-5 text-gray-100"}`,
|
|
131
122
|
className
|
|
132
123
|
),
|
|
124
|
+
"data-umami-event": "call-raise-hand",
|
|
125
|
+
"data-umami-event-state": isHandRaised ? "lower" : "raise",
|
|
126
|
+
disabled: isPending,
|
|
133
127
|
children: /* @__PURE__ */ jsx(Hand, { className: cn("h-5 w-5", isHandRaised ? "fill-brand-100" : "fill-gray-100") })
|
|
134
128
|
}
|
|
135
129
|
);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useRaisedHands.ts","../src/hooks/useHandFocus.ts","../src/ui/RaiseHandButton.tsx"],"names":["useCallStore","useRoom","useEffect"],"mappings":";;;;;;;;;;;;AAMO,IAAM,iBAAiB,MAAM;AAClC,EAAA,MAAM,aAAa,kBAAA,EAAmB;AACtC,EAAA,MAAM,SAAA,GAAY,MAAA,CAAgC,EAAE,CAAA;AACpD,EAAA,MAAM,oBAAA,GAAuB,oBAAA,CAAqB,CAAC,CAAA,KAAM,EAAE,eAAe,CAAA;AAE1E,EAAA,MAAM,MAAA,GAAS,WAAW,SAAA,EAAU;AACpC,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,OAAA,EAAQ;
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useRaisedHands.ts","../src/hooks/useHandFocus.ts","../src/ui/RaiseHandButton.tsx"],"names":["useCallStore","useRoom","useEffect"],"mappings":"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","file":"index.mjs","sourcesContent":["import { useEffect, useCallback, useMemo, useRef } from 'react';\nimport { Participant, RoomEvent } from 'livekit-client';\nimport { useCallStore, useSoundEffectsStore } from '@xipkg/calls-store';\nimport { useCalls, useRoom, useCallsNavigation } from '@xipkg/calls-providers';\nimport { playSound } from '@xipkg/calls-utils';\n\nexport const useRaisedHands = () => {\n const navigation = useCallsNavigation();\n const prevHands = useRef<Record<string, boolean>>({});\n const handRaiseSoundVolume = useSoundEffectsStore((s) => s.handRaiseVolume);\n\n const callId = navigation.getCallId();\n const { room } = useRoom();\n\n const { addRaisedHand, removeRaisedHand } = useCallStore();\n\n const { updateParticipantMetadata, isPending } = useCalls().updateParticipantMetadata;\n\n const isHandRaised = useMemo(() => {\n try {\n const parsed = JSON.parse(room?.localParticipant?.metadata ?? '{}');\n return !!parsed.is_hand_raised;\n } catch {\n return false;\n }\n }, [room?.localParticipant?.metadata]);\n\n const toggleHand = useCallback(async () => {\n if (!room?.localParticipant || !callId) return;\n\n try {\n await updateParticipantMetadata({\n classroom_id: callId,\n is_hand_raised: !isHandRaised,\n });\n } catch (e) {\n console.error('raise hand error', e);\n }\n }, [room?.localParticipant, callId, updateParticipantMetadata, isHandRaised]);\n\n useEffect(() => {\n if (!room) return;\n\n const syncParticipant = (participant: Participant) => {\n try {\n const parsed = JSON.parse(participant.metadata || '{}');\n\n if (!('is_hand_raised' in parsed)) return;\n\n const prev = prevHands.current[participant.identity];\n\n if (parsed.is_hand_raised) {\n addRaisedHand({\n participantId: participant.identity,\n participantName: participant.name ?? participant.identity,\n timestamp: Date.now(),\n });\n\n if (!prev) {\n playSound('handRaise', handRaiseSoundVolume);\n }\n } else {\n removeRaisedHand(participant.identity);\n }\n } catch (e) {\n console.error('metadata parse error', e);\n }\n };\n\n const handler = (_metadata: string | undefined, participant: Participant) => {\n syncParticipant(participant);\n };\n\n room.on(RoomEvent.ParticipantMetadataChanged, handler);\n\n syncParticipant(room.localParticipant);\n room.remoteParticipants.forEach(syncParticipant);\n\n return () => {\n room.off(RoomEvent.ParticipantMetadataChanged, handler);\n };\n }, [room, addRaisedHand, removeRaisedHand, handRaiseSoundVolume]);\n\n return {\n toggleHand,\n isHandRaised,\n isPending: isPending,\n };\n};\n","import { useEffect } from 'react';\nimport { Track } from 'livekit-client';\nimport { useCallStore } from '@xipkg/calls-store';\nimport { useRoom } from '@xipkg/calls-providers';\nimport { useMaybeLayoutContext } from '@livekit/components-react';\n\nexport const useHandFocus = () => {\n const { raisedHands } = useCallStore();\n const { room } = useRoom();\n const layoutContext = useMaybeLayoutContext();\n\n useEffect(() => {\n if (!room || raisedHands.length === 0 || !layoutContext?.pin.dispatch) return;\n\n // Находим участника с самой ранней поднятой рукой\n const earliestHand = raisedHands.reduce((earliest, current) =>\n current.timestamp < earliest.timestamp ? current : earliest,\n );\n\n // Ищем участника в комнате\n const participant = room.getParticipantByIdentity(earliestHand.participantId);\n\n if (participant) {\n console.log(\n '🎯 Auto-focusing on participant with raised hand:',\n earliestHand.participantName,\n );\n\n // Находим трек камеры участника для фокуса\n const cameraTrack = Array.from(participant.videoTrackPublications.values()).find(\n (track) => track.source === 'camera',\n );\n\n if (cameraTrack) {\n // Устанавливаем фокус на участника с поднятой рукой\n layoutContext.pin.dispatch({\n msg: 'set_pin',\n trackReference: {\n participant,\n source: Track.Source.Camera,\n publication: cameraTrack,\n },\n });\n }\n } else {\n console.log('⚠️ Participant not found:', earliestHand.participantId);\n }\n }, [raisedHands, room, layoutContext]);\n};\n","import { Button } from '@xipkg/button';\nimport { Hand } from '@xipkg/icons';\nimport { cn } from '@xipkg/utils';\nimport { useRaisedHands } from '../hooks';\n\nexport const RaiseHandButton = ({ className }: { className?: string }) => {\n const { toggleHand, isHandRaised, isPending } = useRaisedHands();\n\n return (\n <Button\n size=\"icon\"\n variant=\"none\"\n onClick={toggleHand}\n className={cn(\n `relative m-0 h-10 w-10 rounded-lg p-0 ${\n isHandRaised ? 'bg-brand-20 text-brand-100' : 'hover:bg-gray-5 text-gray-100'\n }`,\n className,\n )}\n data-umami-event=\"call-raise-hand\"\n data-umami-event-state={isHandRaised ? 'lower' : 'raise'}\n disabled={isPending}\n >\n <Hand className={cn('h-5 w-5', isHandRaised ? 'fill-brand-100' : 'fill-gray-100')} />\n </Button>\n );\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xipkg/calls-risehand",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@xipkg/icons": "^2.7.0",
|
|
21
21
|
"@xipkg/button": "3.2.0",
|
|
22
|
-
"@xipkg/calls-ui": "
|
|
23
|
-
"@xipkg/calls-utils": "
|
|
24
|
-
"@xipkg/calls-config": "
|
|
25
|
-
"@xipkg/calls-providers": "
|
|
26
|
-
"@xipkg/calls-store": "
|
|
22
|
+
"@xipkg/calls-ui": "^0.0.1",
|
|
23
|
+
"@xipkg/calls-utils": "^0.0.1",
|
|
24
|
+
"@xipkg/calls-config": "^0.0.1",
|
|
25
|
+
"@xipkg/calls-providers": "^0.0.1",
|
|
26
|
+
"@xipkg/calls-store": "^0.0.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@tanstack/react-query-devtools": "5.73.3",
|