@dubsdotapp/expo 0.2.29 → 0.2.31

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 CHANGED
@@ -3797,6 +3797,401 @@ var styles9 = StyleSheet10.create({
3797
3797
  gap: 10
3798
3798
  }
3799
3799
  });
3800
+
3801
+ // src/ui/game/JoinGameSheet.tsx
3802
+ import { useState as useState17, useEffect as useEffect9, useRef as useRef5, useCallback as useCallback14, useMemo as useMemo6 } from "react";
3803
+ import {
3804
+ View as View11,
3805
+ Text as Text11,
3806
+ TouchableOpacity as TouchableOpacity7,
3807
+ ActivityIndicator as ActivityIndicator6,
3808
+ Modal as Modal2,
3809
+ Animated as Animated3,
3810
+ StyleSheet as StyleSheet11,
3811
+ KeyboardAvoidingView as KeyboardAvoidingView3,
3812
+ Platform as Platform5
3813
+ } from "react-native";
3814
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
3815
+ var STATUS_LABELS3 = {
3816
+ building: "Building transaction...",
3817
+ signing: "Approve in wallet...",
3818
+ confirming: "Confirming...",
3819
+ success: "Joined!"
3820
+ };
3821
+ var CUSTOM_GAME_MODE = 6;
3822
+ function JoinGameSheet({
3823
+ visible,
3824
+ onDismiss,
3825
+ game,
3826
+ ImageComponent,
3827
+ shortName,
3828
+ homeColor = "#3B82F6",
3829
+ awayColor = "#EF4444",
3830
+ onSuccess,
3831
+ onError
3832
+ }) {
3833
+ const t = useDubsTheme();
3834
+ const { wallet } = useDubs();
3835
+ const mutation = useJoinGame();
3836
+ const isCustomGame = game.gameMode === CUSTOM_GAME_MODE;
3837
+ const [selectedTeam, setSelectedTeam] = useState17(null);
3838
+ const overlayOpacity = useRef5(new Animated3.Value(0)).current;
3839
+ useEffect9(() => {
3840
+ Animated3.timing(overlayOpacity, {
3841
+ toValue: visible ? 1 : 0,
3842
+ duration: 250,
3843
+ useNativeDriver: true
3844
+ }).start();
3845
+ }, [visible, overlayOpacity]);
3846
+ useEffect9(() => {
3847
+ if (visible) {
3848
+ setSelectedTeam(isCustomGame ? "away" : null);
3849
+ mutation.reset();
3850
+ }
3851
+ }, [visible]);
3852
+ useEffect9(() => {
3853
+ if (mutation.status === "success" && mutation.data) {
3854
+ onSuccess?.(mutation.data);
3855
+ const timer = setTimeout(() => {
3856
+ onDismiss();
3857
+ }, 1500);
3858
+ return () => clearTimeout(timer);
3859
+ }
3860
+ }, [mutation.status, mutation.data]);
3861
+ useEffect9(() => {
3862
+ if (mutation.status === "error" && mutation.error) {
3863
+ onError?.(mutation.error);
3864
+ }
3865
+ }, [mutation.status, mutation.error]);
3866
+ const opponents = game.opponents || [];
3867
+ const bettors = game.bettors || [];
3868
+ const totalPool = game.totalPool || 0;
3869
+ const homePool = game.homePool || 0;
3870
+ const awayPool = game.awayPool || 0;
3871
+ const buyIn = game.buyIn;
3872
+ const { homeOdds, awayOdds, homeBets, awayBets } = useMemo6(() => ({
3873
+ homeOdds: homePool > 0 ? (totalPool / homePool).toFixed(2) : "\u2014",
3874
+ awayOdds: awayPool > 0 ? (totalPool / awayPool).toFixed(2) : "\u2014",
3875
+ homeBets: bettors.filter((b) => b.team === "home").length,
3876
+ awayBets: bettors.filter((b) => b.team === "away").length
3877
+ }), [totalPool, homePool, awayPool, bettors]);
3878
+ const poolAfterJoin = totalPool + buyIn;
3879
+ const selectedOdds = selectedTeam === "home" ? homeOdds : selectedTeam === "away" ? awayOdds : "\u2014";
3880
+ const potentialWinnings = selectedOdds !== "\u2014" ? (parseFloat(selectedOdds) * buyIn).toFixed(4) : "\u2014";
3881
+ const homeName = shortName ? shortName(opponents[0]?.name) : opponents[0]?.name || "Home";
3882
+ const awayName = shortName ? shortName(opponents[1]?.name) : opponents[1]?.name || "Away";
3883
+ const selectedName = selectedTeam === "home" ? homeName : selectedTeam === "away" ? awayName : "\u2014";
3884
+ const alreadyJoined = useMemo6(() => {
3885
+ if (!wallet.publicKey) return false;
3886
+ const addr = wallet.publicKey.toBase58();
3887
+ return bettors.some((b) => b.wallet === addr);
3888
+ }, [bettors, wallet.publicKey]);
3889
+ const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
3890
+ const canJoin = selectedTeam !== null && !isMutating && mutation.status !== "success" && !alreadyJoined;
3891
+ const handleJoin = useCallback14(async () => {
3892
+ if (!selectedTeam || !wallet.publicKey) return;
3893
+ try {
3894
+ await mutation.execute({
3895
+ playerWallet: wallet.publicKey.toBase58(),
3896
+ gameId: game.gameId,
3897
+ teamChoice: selectedTeam,
3898
+ amount: buyIn
3899
+ });
3900
+ } catch {
3901
+ }
3902
+ }, [selectedTeam, wallet.publicKey, mutation.execute, game.gameId, buyIn]);
3903
+ const statusLabel = STATUS_LABELS3[mutation.status] || "";
3904
+ return /* @__PURE__ */ jsxs11(
3905
+ Modal2,
3906
+ {
3907
+ visible,
3908
+ animationType: "slide",
3909
+ transparent: true,
3910
+ onRequestClose: onDismiss,
3911
+ children: [
3912
+ /* @__PURE__ */ jsx13(Animated3.View, { style: [styles10.overlay, { opacity: overlayOpacity }], children: /* @__PURE__ */ jsx13(TouchableOpacity7, { style: styles10.overlayTap, activeOpacity: 1, onPress: onDismiss }) }),
3913
+ /* @__PURE__ */ jsx13(
3914
+ KeyboardAvoidingView3,
3915
+ {
3916
+ style: styles10.keyboardView,
3917
+ behavior: Platform5.OS === "ios" ? "padding" : void 0,
3918
+ children: /* @__PURE__ */ jsx13(View11, { style: styles10.sheetPositioner, children: /* @__PURE__ */ jsxs11(View11, { style: [styles10.sheet, { backgroundColor: t.background }], children: [
3919
+ /* @__PURE__ */ jsx13(View11, { style: styles10.handleRow, children: /* @__PURE__ */ jsx13(View11, { style: [styles10.handle, { backgroundColor: t.textMuted }] }) }),
3920
+ /* @__PURE__ */ jsxs11(View11, { style: styles10.header, children: [
3921
+ /* @__PURE__ */ jsx13(Text11, { style: [styles10.headerTitle, { color: t.text }], children: "Join Game" }),
3922
+ /* @__PURE__ */ jsx13(TouchableOpacity7, { onPress: onDismiss, activeOpacity: 0.8, children: /* @__PURE__ */ jsx13(Text11, { style: [styles10.closeButton, { color: t.textMuted }], children: "\u2715" }) })
3923
+ ] }),
3924
+ !isCustomGame && /* @__PURE__ */ jsxs11(View11, { style: styles10.section, children: [
3925
+ /* @__PURE__ */ jsx13(Text11, { style: [styles10.sectionLabel, { color: t.textSecondary }], children: "Pick Your Side" }),
3926
+ /* @__PURE__ */ jsxs11(View11, { style: styles10.teamsRow, children: [
3927
+ /* @__PURE__ */ jsx13(
3928
+ TeamButton,
3929
+ {
3930
+ name: homeName,
3931
+ imageUrl: opponents[0]?.imageUrl,
3932
+ odds: homeOdds,
3933
+ bets: homeBets,
3934
+ color: homeColor,
3935
+ selected: selectedTeam === "home",
3936
+ onPress: () => setSelectedTeam("home"),
3937
+ ImageComponent,
3938
+ t
3939
+ }
3940
+ ),
3941
+ /* @__PURE__ */ jsx13(
3942
+ TeamButton,
3943
+ {
3944
+ name: awayName,
3945
+ imageUrl: opponents[1]?.imageUrl,
3946
+ odds: awayOdds,
3947
+ bets: awayBets,
3948
+ color: awayColor,
3949
+ selected: selectedTeam === "away",
3950
+ onPress: () => setSelectedTeam("away"),
3951
+ ImageComponent,
3952
+ t
3953
+ }
3954
+ )
3955
+ ] })
3956
+ ] }),
3957
+ /* @__PURE__ */ jsxs11(View11, { style: [styles10.summaryCard, { backgroundColor: t.surface, borderColor: t.border }], children: [
3958
+ /* @__PURE__ */ jsxs11(View11, { style: styles10.summaryRow, children: [
3959
+ /* @__PURE__ */ jsx13(Text11, { style: [styles10.summaryLabel, { color: t.textMuted }], children: "Buy-in" }),
3960
+ /* @__PURE__ */ jsxs11(Text11, { style: [styles10.summaryValue, { color: t.text }], children: [
3961
+ buyIn,
3962
+ " SOL"
3963
+ ] })
3964
+ ] }),
3965
+ /* @__PURE__ */ jsx13(View11, { style: [styles10.summarySep, { backgroundColor: t.border }] }),
3966
+ /* @__PURE__ */ jsxs11(View11, { style: styles10.summaryRow, children: [
3967
+ /* @__PURE__ */ jsx13(Text11, { style: [styles10.summaryLabel, { color: t.textMuted }], children: "Your side" }),
3968
+ /* @__PURE__ */ jsx13(Text11, { style: [styles10.summaryValue, { color: t.text }], children: selectedName })
3969
+ ] }),
3970
+ /* @__PURE__ */ jsx13(View11, { style: [styles10.summarySep, { backgroundColor: t.border }] }),
3971
+ /* @__PURE__ */ jsxs11(View11, { style: styles10.summaryRow, children: [
3972
+ /* @__PURE__ */ jsx13(Text11, { style: [styles10.summaryLabel, { color: t.textMuted }], children: "Total pool" }),
3973
+ /* @__PURE__ */ jsxs11(Text11, { style: [styles10.summaryValue, { color: t.text }], children: [
3974
+ poolAfterJoin,
3975
+ " SOL"
3976
+ ] })
3977
+ ] }),
3978
+ /* @__PURE__ */ jsx13(View11, { style: [styles10.summarySep, { backgroundColor: t.border }] }),
3979
+ /* @__PURE__ */ jsxs11(View11, { style: styles10.summaryRow, children: [
3980
+ /* @__PURE__ */ jsx13(Text11, { style: [styles10.summaryLabel, { color: t.textMuted }], children: "Potential winnings" }),
3981
+ /* @__PURE__ */ jsx13(Text11, { style: [styles10.summaryValue, { color: t.success }], children: potentialWinnings !== "\u2014" ? `${potentialWinnings} SOL` : "\u2014" })
3982
+ ] })
3983
+ ] }),
3984
+ alreadyJoined && /* @__PURE__ */ jsx13(View11, { style: [styles10.errorBox, { backgroundColor: t.surface, borderColor: t.border }], children: /* @__PURE__ */ jsx13(Text11, { style: [styles10.errorText, { color: t.textMuted }], children: "You've already joined this game." }) }),
3985
+ mutation.error && /* @__PURE__ */ jsx13(View11, { style: [styles10.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ jsx13(Text11, { style: [styles10.errorText, { color: t.errorText }], children: mutation.error.message }) }),
3986
+ /* @__PURE__ */ jsx13(
3987
+ TouchableOpacity7,
3988
+ {
3989
+ style: [
3990
+ styles10.ctaButton,
3991
+ { backgroundColor: canJoin ? t.accent : t.border }
3992
+ ],
3993
+ disabled: !canJoin,
3994
+ onPress: handleJoin,
3995
+ activeOpacity: 0.8,
3996
+ children: isMutating ? /* @__PURE__ */ jsxs11(View11, { style: styles10.ctaLoading, children: [
3997
+ /* @__PURE__ */ jsx13(ActivityIndicator6, { size: "small", color: "#FFFFFF" }),
3998
+ /* @__PURE__ */ jsx13(Text11, { style: styles10.ctaText, children: statusLabel })
3999
+ ] }) : mutation.status === "success" ? /* @__PURE__ */ jsx13(Text11, { style: styles10.ctaText, children: STATUS_LABELS3.success }) : /* @__PURE__ */ jsx13(Text11, { style: [styles10.ctaText, !canJoin && { opacity: 0.5 }], children: alreadyJoined ? "Already Joined" : selectedTeam ? `Join Game \u2014 ${buyIn} SOL` : "Pick a side to join" })
4000
+ }
4001
+ )
4002
+ ] }) })
4003
+ }
4004
+ )
4005
+ ]
4006
+ }
4007
+ );
4008
+ }
4009
+ function TeamButton({
4010
+ name,
4011
+ imageUrl,
4012
+ odds,
4013
+ bets,
4014
+ color,
4015
+ selected,
4016
+ onPress,
4017
+ ImageComponent,
4018
+ t
4019
+ }) {
4020
+ const [imgFailed, setImgFailed] = useState17(false);
4021
+ const Img = ImageComponent || __require("react-native").Image;
4022
+ const showImage = imageUrl && !imgFailed;
4023
+ return /* @__PURE__ */ jsxs11(
4024
+ TouchableOpacity7,
4025
+ {
4026
+ style: [styles10.teamOption, { borderColor: selected ? color : t.border, backgroundColor: selected ? color + "15" : t.background }],
4027
+ onPress,
4028
+ activeOpacity: 0.7,
4029
+ children: [
4030
+ showImage ? /* @__PURE__ */ jsx13(Img, { source: { uri: imageUrl }, style: styles10.teamLogo, resizeMode: "contain", onError: () => setImgFailed(true) }) : /* @__PURE__ */ jsx13(View11, { style: [styles10.teamLogo, styles10.teamLogoPlaceholder] }),
4031
+ /* @__PURE__ */ jsx13(Text11, { style: [styles10.teamName, { color: t.text }], numberOfLines: 1, children: name }),
4032
+ /* @__PURE__ */ jsxs11(Text11, { style: [styles10.teamOdds, { color }], children: [
4033
+ odds,
4034
+ "x"
4035
+ ] }),
4036
+ /* @__PURE__ */ jsxs11(Text11, { style: [styles10.teamBets, { color: t.textMuted }], children: [
4037
+ bets,
4038
+ " ",
4039
+ bets === 1 ? "bet" : "bets"
4040
+ ] }),
4041
+ selected && /* @__PURE__ */ jsx13(View11, { style: [styles10.teamBadge, { backgroundColor: color }], children: /* @__PURE__ */ jsx13(Text11, { style: styles10.teamBadgeText, children: "Selected" }) })
4042
+ ]
4043
+ }
4044
+ );
4045
+ }
4046
+ var styles10 = StyleSheet11.create({
4047
+ overlay: {
4048
+ ...StyleSheet11.absoluteFillObject,
4049
+ backgroundColor: "rgba(0,0,0,0.5)"
4050
+ },
4051
+ overlayTap: {
4052
+ flex: 1
4053
+ },
4054
+ keyboardView: {
4055
+ flex: 1,
4056
+ justifyContent: "flex-end"
4057
+ },
4058
+ sheetPositioner: {
4059
+ justifyContent: "flex-end"
4060
+ },
4061
+ sheet: {
4062
+ borderTopLeftRadius: 24,
4063
+ borderTopRightRadius: 24,
4064
+ paddingHorizontal: 20,
4065
+ paddingBottom: 40
4066
+ },
4067
+ handleRow: {
4068
+ alignItems: "center",
4069
+ paddingTop: 10,
4070
+ paddingBottom: 8
4071
+ },
4072
+ handle: {
4073
+ width: 36,
4074
+ height: 4,
4075
+ borderRadius: 2,
4076
+ opacity: 0.4
4077
+ },
4078
+ header: {
4079
+ flexDirection: "row",
4080
+ alignItems: "center",
4081
+ justifyContent: "space-between",
4082
+ paddingVertical: 12
4083
+ },
4084
+ headerTitle: {
4085
+ fontSize: 20,
4086
+ fontWeight: "700"
4087
+ },
4088
+ closeButton: {
4089
+ fontSize: 20,
4090
+ padding: 4
4091
+ },
4092
+ section: {
4093
+ gap: 12,
4094
+ paddingTop: 8
4095
+ },
4096
+ sectionLabel: {
4097
+ fontSize: 15,
4098
+ fontWeight: "600"
4099
+ },
4100
+ teamsRow: {
4101
+ flexDirection: "row",
4102
+ gap: 12
4103
+ },
4104
+ summaryCard: {
4105
+ marginTop: 20,
4106
+ borderRadius: 16,
4107
+ borderWidth: 1,
4108
+ overflow: "hidden"
4109
+ },
4110
+ summaryRow: {
4111
+ flexDirection: "row",
4112
+ alignItems: "center",
4113
+ justifyContent: "space-between",
4114
+ paddingHorizontal: 16,
4115
+ paddingVertical: 14
4116
+ },
4117
+ summaryLabel: {
4118
+ fontSize: 14
4119
+ },
4120
+ summaryValue: {
4121
+ fontSize: 15,
4122
+ fontWeight: "700"
4123
+ },
4124
+ summarySep: {
4125
+ height: 1,
4126
+ marginHorizontal: 16
4127
+ },
4128
+ errorBox: {
4129
+ marginTop: 16,
4130
+ borderRadius: 12,
4131
+ borderWidth: 1,
4132
+ padding: 12
4133
+ },
4134
+ errorText: {
4135
+ fontSize: 13,
4136
+ fontWeight: "500"
4137
+ },
4138
+ ctaButton: {
4139
+ marginTop: 20,
4140
+ height: 56,
4141
+ borderRadius: 14,
4142
+ justifyContent: "center",
4143
+ alignItems: "center"
4144
+ },
4145
+ ctaText: {
4146
+ color: "#FFFFFF",
4147
+ fontSize: 16,
4148
+ fontWeight: "700"
4149
+ },
4150
+ ctaLoading: {
4151
+ flexDirection: "row",
4152
+ alignItems: "center",
4153
+ gap: 10
4154
+ },
4155
+ // Team button styles
4156
+ teamOption: {
4157
+ flex: 1,
4158
+ borderWidth: 2,
4159
+ borderRadius: 16,
4160
+ padding: 16,
4161
+ alignItems: "center",
4162
+ gap: 8
4163
+ },
4164
+ teamLogo: {
4165
+ width: 48,
4166
+ height: 48,
4167
+ borderRadius: 24
4168
+ },
4169
+ teamLogoPlaceholder: {
4170
+ backgroundColor: "rgba(128,128,128,0.2)"
4171
+ },
4172
+ teamName: {
4173
+ fontSize: 15,
4174
+ fontWeight: "700"
4175
+ },
4176
+ teamOdds: {
4177
+ fontSize: 20,
4178
+ fontWeight: "800"
4179
+ },
4180
+ teamBets: {
4181
+ fontSize: 12
4182
+ },
4183
+ teamBadge: {
4184
+ borderRadius: 8,
4185
+ paddingHorizontal: 12,
4186
+ paddingVertical: 4,
4187
+ marginTop: 4
4188
+ },
4189
+ teamBadgeText: {
4190
+ color: "#FFF",
4191
+ fontSize: 12,
4192
+ fontWeight: "700"
4193
+ }
4194
+ });
3800
4195
  export {
3801
4196
  AuthGate,
3802
4197
  ConnectWalletScreen,
@@ -3808,6 +4203,7 @@ export {
3808
4203
  DubsProvider,
3809
4204
  GamePoster,
3810
4205
  JoinGameButton,
4206
+ JoinGameSheet,
3811
4207
  LivePoolsCard,
3812
4208
  MwaWalletAdapter,
3813
4209
  NETWORK_CONFIG,