share modal
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
import {
|
||||
Feather,
|
||||
FontAwesome,
|
||||
MaterialCommunityIcons,
|
||||
} from "@expo/vector-icons";
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
@@ -15,21 +20,18 @@ import {
|
||||
View,
|
||||
} from "react-native";
|
||||
import { SheetManager } from "react-native-actions-sheet";
|
||||
import {
|
||||
Feather,
|
||||
FontAwesome,
|
||||
MaterialCommunityIcons,
|
||||
} from "@expo/vector-icons";
|
||||
|
||||
import AppActionSheet from "../AppActionSheet";
|
||||
import { Palette } from "../../styles";
|
||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||
import { isWeb } from "../../hooks/useLayoutType";
|
||||
import { BlurView } from "expo-blur";
|
||||
import { setGlobal } from "reactn";
|
||||
import {
|
||||
musiclandShareHeading,
|
||||
musiclandShareMessage,
|
||||
musiclandShareUrl,
|
||||
} from "../../data";
|
||||
import { isWeb } from "../../hooks/useLayoutType";
|
||||
import { Palette } from "../../styles";
|
||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||
import AppActionSheet from "../AppActionSheet";
|
||||
|
||||
const ShareModal = ({ payload }) => {
|
||||
const heading = payload?.heading ?? musiclandShareHeading;
|
||||
@@ -38,9 +40,12 @@ const ShareModal = ({ payload }) => {
|
||||
const shareMessage = payload?.shareMessage ?? musiclandShareMessage;
|
||||
const linkLabel = payload?.linkLabel ?? url;
|
||||
const sectionTitle = payload?.sectionTitle ?? "Partager sur...";
|
||||
const qrTitle = payload?.qrTitle ?? "Scannez le QR-code";
|
||||
const qrUrl = payload?.qrUrl ?? musiclandShareUrl;
|
||||
|
||||
const [copied, setCopied] = useState(false);
|
||||
const copyTimeout = useRef(null);
|
||||
const qrOpenTimeout = useRef(null);
|
||||
|
||||
const closeSheet = useCallback(() => {
|
||||
SheetManager.hide("Share");
|
||||
@@ -61,6 +66,9 @@ const ShareModal = ({ payload }) => {
|
||||
if (copyTimeout.current) {
|
||||
clearTimeout(copyTimeout.current);
|
||||
}
|
||||
if (qrOpenTimeout.current) {
|
||||
clearTimeout(qrOpenTimeout.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -123,6 +131,22 @@ const ShareModal = ({ payload }) => {
|
||||
|
||||
const handleShareOption = useCallback(
|
||||
async (option) => {
|
||||
if (option?.type === "qr") {
|
||||
const qrTitleValue = qrTitle;
|
||||
|
||||
closeSheet();
|
||||
qrOpenTimeout.current = setTimeout(() => {
|
||||
setGlobal({
|
||||
shareQrModal: {
|
||||
visible: true,
|
||||
url: qrUrl,
|
||||
title: qrTitleValue,
|
||||
},
|
||||
});
|
||||
}, 200);
|
||||
return;
|
||||
}
|
||||
|
||||
const target = option?.target;
|
||||
|
||||
if (!target) {
|
||||
@@ -151,7 +175,7 @@ const ShareModal = ({ payload }) => {
|
||||
await handleSystemShare();
|
||||
closeSheet();
|
||||
},
|
||||
[closeSheet, handleSystemShare]
|
||||
[closeSheet, handleSystemShare, qrTitle, qrUrl]
|
||||
);
|
||||
|
||||
const onSystemShare = useCallback(async () => {
|
||||
@@ -193,11 +217,11 @@ const ShareModal = ({ payload }) => {
|
||||
},
|
||||
{
|
||||
key: "qr",
|
||||
type: "qr",
|
||||
label: "Partager par QR-code",
|
||||
Icon: (props) => (
|
||||
<MaterialCommunityIcons name="qrcode-scan" {...props} />
|
||||
),
|
||||
target: `https://api.qrserver.com/v1/create-qr-code/?size=512x512&data=${encodedUrl}`,
|
||||
},
|
||||
];
|
||||
}, [encodedShareText, encodedUrl, payload?.options, shareTitle]);
|
||||
@@ -205,7 +229,12 @@ const ShareModal = ({ payload }) => {
|
||||
return (
|
||||
<AppActionSheet id="Share">
|
||||
<View style={styles.container}>
|
||||
<View style={styles.card}>
|
||||
<BlurView
|
||||
style={[styles.card, styles.blurCard]}
|
||||
tint="dark"
|
||||
intensity={40}
|
||||
experimentalBlurMethod="dimezisBlurView"
|
||||
>
|
||||
<Text style={styles.heading}>{heading}</Text>
|
||||
<View style={styles.linkRow}>
|
||||
<Text numberOfLines={1} style={styles.linkText}>
|
||||
@@ -232,31 +261,39 @@ const ShareModal = ({ payload }) => {
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
{copied ? (
|
||||
<Text style={styles.copiedText}>Lien copie</Text>
|
||||
) : null}
|
||||
</View>
|
||||
{copied ? <Text style={styles.copiedText}>Lien copié</Text> : null}
|
||||
</BlurView>
|
||||
|
||||
<View style={styles.card}>
|
||||
<BlurView
|
||||
intensity={70}
|
||||
experimentalBlurMethod="dimezisBlurView"
|
||||
style={styles.card}
|
||||
>
|
||||
<Text style={styles.sectionHeading}>{sectionTitle}</Text>
|
||||
<View style={styles.optionsList}>
|
||||
{shareOptions.map((option) => {
|
||||
{shareOptions.map((option, index) => {
|
||||
const Icon = option?.Icon ?? Feather;
|
||||
return (
|
||||
<Pressable
|
||||
key={option?.key}
|
||||
onPress={() => handleShareOption(option)}
|
||||
style={styles.optionRow}
|
||||
<BlurView
|
||||
key={option?.key || index}
|
||||
style={styles.optionBlur}
|
||||
intensity={40}
|
||||
experimentalBlurMethod="dimezisBlurView"
|
||||
>
|
||||
<View style={styles.optionIconWrapper}>
|
||||
<Icon size={18} color={Palette.white} />
|
||||
</View>
|
||||
<Text style={styles.optionLabel}>{option?.label}</Text>
|
||||
</Pressable>
|
||||
<Pressable
|
||||
onPress={() => handleShareOption(option)}
|
||||
style={styles.optionRow}
|
||||
>
|
||||
<View style={styles.optionIconWrapper}>
|
||||
<Icon size={18} color={Palette.white} />
|
||||
</View>
|
||||
<Text style={styles.optionLabel}>{option?.label}</Text>
|
||||
</Pressable>
|
||||
</BlurView>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</View>
|
||||
</BlurView>
|
||||
</View>
|
||||
</AppActionSheet>
|
||||
);
|
||||
@@ -267,7 +304,8 @@ const styles = StyleSheet.create({
|
||||
gap: 24,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: Palette.glass,
|
||||
// backgroundColor: Palette.glass,
|
||||
overflow: "hidden",
|
||||
borderRadius: 24,
|
||||
borderWidth: 1,
|
||||
borderColor: "rgba(255, 255, 255, 0.08)",
|
||||
@@ -275,6 +313,9 @@ const styles = StyleSheet.create({
|
||||
paddingVertical: 18,
|
||||
gap: 16,
|
||||
},
|
||||
blurCard: {
|
||||
overflow: "hidden",
|
||||
},
|
||||
heading: {
|
||||
fontSize: 20,
|
||||
color: Palette.white,
|
||||
@@ -325,11 +366,15 @@ const styles = StyleSheet.create({
|
||||
optionsList: {
|
||||
gap: 12,
|
||||
},
|
||||
optionBlur: {
|
||||
borderRadius: 18,
|
||||
overflow: "hidden",
|
||||
},
|
||||
optionRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
backgroundColor: "rgba(255, 255, 255, 0.04)",
|
||||
borderRadius: 18,
|
||||
// borderRadius: 18,
|
||||
paddingHorizontal: 14,
|
||||
paddingVertical: 14,
|
||||
gap: 14,
|
||||
@@ -351,4 +396,3 @@ const styles = StyleSheet.create({
|
||||
});
|
||||
|
||||
export default ShareModal;
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import React, { useMemo } from "react";
|
||||
import { BlurView } from "expo-blur";
|
||||
import { Platform, Pressable, StyleSheet, Text, View } from "react-native";
|
||||
import { Feather } from "@expo/vector-icons";
|
||||
import { Portal } from "@gorhom/portal";
|
||||
|
||||
import QrCode from "../QrCode";
|
||||
import { Palette } from "../../styles";
|
||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||
|
||||
const ShareQrModal = ({ visible, onClose, url, title = "Scannez le QR-code" }) => {
|
||||
const shareUrl = useMemo(() => url, [url]);
|
||||
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const blurIntensity = Platform.select({ ios: 40, default: 20 });
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<View style={StyleSheet.absoluteFill} pointerEvents="box-none">
|
||||
<Pressable
|
||||
onPress={onClose}
|
||||
style={[StyleSheet.absoluteFill, styles.backdrop]}
|
||||
/>
|
||||
|
||||
<View style={styles.centerWrapper} pointerEvents="box-none">
|
||||
<BlurView intensity={blurIntensity} tint="dark" style={styles.modalCard}>
|
||||
<Pressable onPress={onClose} style={styles.closeButton} hitSlop={10}>
|
||||
<Feather name="x" size={20} color={Palette.white} />
|
||||
</Pressable>
|
||||
|
||||
<View style={styles.content}>
|
||||
<Text style={styles.title}>{title}</Text>
|
||||
<Text style={styles.subtitle}>
|
||||
Partage ce code pour guider tes contacts directement vers MusicLand.
|
||||
</Text>
|
||||
|
||||
<View style={styles.qrWrapper}>
|
||||
<QrCode value={shareUrl} size={220} backgroundColor="transparent" />
|
||||
</View>
|
||||
|
||||
<Text numberOfLines={1} ellipsizeMode="middle" style={styles.linkText}>
|
||||
{shareUrl}
|
||||
</Text>
|
||||
</View>
|
||||
</BlurView>
|
||||
</View>
|
||||
</View>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
backdrop: {
|
||||
backgroundColor: "rgba(0, 0, 0, 0.65)",
|
||||
},
|
||||
centerWrapper: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: 24,
|
||||
},
|
||||
modalCard: {
|
||||
width: 360,
|
||||
maxWidth: "90%",
|
||||
borderRadius: 28,
|
||||
overflow: "hidden",
|
||||
paddingHorizontal: 24,
|
||||
paddingVertical: 32,
|
||||
backgroundColor: Palette.glass,
|
||||
},
|
||||
closeButton: {
|
||||
position: "absolute",
|
||||
top: 18,
|
||||
right: 18,
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: 18,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "rgba(255, 255, 255, 0.12)",
|
||||
},
|
||||
content: {
|
||||
alignItems: "center",
|
||||
gap: 18,
|
||||
},
|
||||
title: {
|
||||
fontSize: 20,
|
||||
color: Palette.white,
|
||||
fontFamily: FONT_FAMILY.HelveticaNeueMedium,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 14,
|
||||
color: Palette.white,
|
||||
opacity: 0.8,
|
||||
textAlign: "center",
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
paddingHorizontal: 8,
|
||||
},
|
||||
qrWrapper: {
|
||||
padding: 16,
|
||||
borderRadius: 24,
|
||||
backgroundColor: "rgba(255, 255, 255, 0.08)",
|
||||
},
|
||||
linkText: {
|
||||
fontSize: 13,
|
||||
color: Palette.white,
|
||||
opacity: 0.9,
|
||||
textAlign: "center",
|
||||
fontFamily: FONT_FAMILY.InterMedium,
|
||||
},
|
||||
});
|
||||
|
||||
export default ShareQrModal;
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from "react";
|
||||
import { useGlobal } from "reactn";
|
||||
|
||||
import { musiclandShareUrl } from "../../data";
|
||||
import ShareQrModal from "./ShareQrModal";
|
||||
|
||||
const ShareQrModalContainer = () => {
|
||||
const [shareQrModal, setShareQrModal] = useGlobal("shareQrModal");
|
||||
|
||||
const { visible, url, title } = shareQrModal || {};
|
||||
|
||||
const handleClose = () => {
|
||||
setShareQrModal({
|
||||
visible: false,
|
||||
url: null,
|
||||
title: "",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<ShareQrModal
|
||||
visible={!!visible}
|
||||
url={url || musiclandShareUrl}
|
||||
title={title || "Scannez le QR-code"}
|
||||
onClose={handleClose}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ShareQrModalContainer;
|
||||
Reference in New Issue
Block a user