clear more ticket, sub and design
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { BlurView } from "expo-blur";
|
||||
import React from "react";
|
||||
import { Image, TextInput, View } from "react-native";
|
||||
import React, { useCallback, useEffect, useRef } from "react";
|
||||
import { Image, Pressable, TextInput } from "react-native";
|
||||
import { icons } from "../assets";
|
||||
import { Palette } from "../styles";
|
||||
import { FONT_FAMILY } from "../styles/Fonts";
|
||||
@@ -10,8 +10,99 @@ const SearchBar = ({
|
||||
placeholder = "Que souhaites-tu écouter?",
|
||||
textInputProps = {},
|
||||
}) => {
|
||||
const inputRef = useRef(null);
|
||||
const hasForwardedFocusRef = useRef(false);
|
||||
const focusFallbackRef = useRef(null);
|
||||
|
||||
const {
|
||||
onFocus: onFocusProp,
|
||||
onPressIn: onPressInProp,
|
||||
ref: textInputRefProp,
|
||||
...restTextInputProps
|
||||
} = textInputProps;
|
||||
|
||||
const forwardFocus = useCallback(
|
||||
(event) => {
|
||||
if (hasForwardedFocusRef.current) return;
|
||||
hasForwardedFocusRef.current = true;
|
||||
onFocusProp?.(event);
|
||||
},
|
||||
[onFocusProp],
|
||||
);
|
||||
|
||||
const handleFocus = useCallback(
|
||||
(event) => {
|
||||
forwardFocus(event);
|
||||
},
|
||||
[forwardFocus],
|
||||
);
|
||||
|
||||
const focusInput = useCallback(() => {
|
||||
const node = inputRef.current;
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
typeof node.isFocused === "function" &&
|
||||
node.isFocused() &&
|
||||
hasForwardedFocusRef.current
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
hasForwardedFocusRef.current = false;
|
||||
node.focus?.();
|
||||
|
||||
if (focusFallbackRef.current) {
|
||||
cancelAnimationFrame(focusFallbackRef.current);
|
||||
}
|
||||
|
||||
focusFallbackRef.current = requestAnimationFrame(() => {
|
||||
// Some platforms do not propagate the focus event when focus() is called programmatically.
|
||||
if (!hasForwardedFocusRef.current) {
|
||||
forwardFocus();
|
||||
}
|
||||
|
||||
if (typeof node.isFocused === "function" && !node.isFocused()) {
|
||||
node.focus?.();
|
||||
}
|
||||
});
|
||||
}, [forwardFocus]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (focusFallbackRef.current) {
|
||||
cancelAnimationFrame(focusFallbackRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const setRefs = useCallback(
|
||||
(node) => {
|
||||
inputRef.current = node;
|
||||
|
||||
if (typeof textInputRefProp === "function") {
|
||||
textInputRefProp(node);
|
||||
} else if (textInputRefProp) {
|
||||
textInputRefProp.current = node;
|
||||
}
|
||||
},
|
||||
[textInputRefProp],
|
||||
);
|
||||
|
||||
const handleInputPressIn = useCallback(
|
||||
(event) => {
|
||||
focusInput();
|
||||
onPressInProp?.(event);
|
||||
},
|
||||
[focusInput, onPressInProp],
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={{ borderRadius: 12, overflow: "hidden" }}>
|
||||
<Pressable
|
||||
onPressIn={focusInput}
|
||||
style={{ borderRadius: 12, overflow: "hidden" }}
|
||||
>
|
||||
<BlurView
|
||||
intensity={80}
|
||||
style={{
|
||||
@@ -24,6 +115,7 @@ const SearchBar = ({
|
||||
>
|
||||
<Image source={icons.search} />
|
||||
<TextInput
|
||||
ref={setRefs}
|
||||
placeholder={placeholder}
|
||||
placeholderTextColor={Palette.gray}
|
||||
style={{
|
||||
@@ -32,10 +124,12 @@ const SearchBar = ({
|
||||
fontFamily: FONT_FAMILY.HelveticaNeueRegular,
|
||||
flex: 1,
|
||||
}}
|
||||
{...textInputProps}
|
||||
onPressIn={handleInputPressIn}
|
||||
onFocus={handleFocus}
|
||||
{...restTextInputProps}
|
||||
/>
|
||||
</BlurView>
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import React from "react";
|
||||
import { Image } from "react-native";
|
||||
import { subBadges } from "../assets";
|
||||
|
||||
const allowedLevels = new Set(["starter", "pro", "premium"]);
|
||||
|
||||
const normalizeLevel = (value) => {
|
||||
if (typeof value !== "string") {
|
||||
return null;
|
||||
}
|
||||
const normalized = value.trim().toLowerCase();
|
||||
return allowedLevels.has(normalized) ? normalized : null;
|
||||
};
|
||||
|
||||
const SubscriptionBadge = ({ level = null, size = 20, style = null }) => {
|
||||
const normalized = normalizeLevel(level);
|
||||
const source = normalized ? subBadges[normalized] : null;
|
||||
|
||||
if (!source) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Image
|
||||
source={source}
|
||||
style={[{ width: size, height: size }, style]}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(SubscriptionBadge);
|
||||
@@ -18,7 +18,7 @@ import { isWeb } from "../../hooks/useLayoutType";
|
||||
import CreditAmount from "../CreditAmount";
|
||||
import { useStripe } from "../../providers/StripeProvider";
|
||||
|
||||
const WEB_MODAL_MAX_WIDTH = 1000;
|
||||
const WEB_MODAL_MAX_WIDTH = 820;
|
||||
const formatCurrency = (amount, currency = "eur") => {
|
||||
if (typeof amount !== "number") {
|
||||
return null;
|
||||
@@ -229,14 +229,6 @@ function CoinPackCard({
|
||||
) : null}
|
||||
{pack?.name ? <Text style={styles.packName}>{pack.name}</Text> : null}
|
||||
</View>
|
||||
<View style={styles.perksList}>
|
||||
<Text style={styles.perkItem}>
|
||||
- Diffusion sur mes plates formes de streaming
|
||||
</Text>
|
||||
<Text style={styles.perkItem}>
|
||||
*Eligible au Hit parade Chanson/Video
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.priceBlock}>
|
||||
{formattedPrice ? (
|
||||
<Text style={styles.packPrice}>{formattedPrice}</Text>
|
||||
@@ -388,6 +380,9 @@ const CoinPackModal = ({ visible, onClose }) => {
|
||||
width: "100%",
|
||||
maxWidth: modalMaxWidth,
|
||||
alignSelf: "center",
|
||||
borderWidth: isWeb ? 1 : 0,
|
||||
borderColor: "rgba(255,255,255,0.16)",
|
||||
backgroundColor: isWeb ? "rgba(12, 10, 18, 0.85)" : undefined,
|
||||
}}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
@@ -452,6 +447,7 @@ const styles = StyleSheet.create({
|
||||
gap: 24,
|
||||
alignItems: "center",
|
||||
paddingBottom: gutters,
|
||||
paddingHorizontal: isWeb ? gutters * 1.5 : 0,
|
||||
width: "100%",
|
||||
maxWidth: isWeb ? WEB_MODAL_MAX_WIDTH : undefined,
|
||||
},
|
||||
@@ -503,7 +499,7 @@ const styles = StyleSheet.create({
|
||||
maxWidth: isWeb ? WEB_MODAL_MAX_WIDTH : "100%",
|
||||
alignSelf: "center",
|
||||
gap: gutters,
|
||||
paddingHorizontal: isWeb ? 8 : 0,
|
||||
paddingHorizontal: isWeb ? gutters * 1.5 : 0,
|
||||
},
|
||||
packListWeb: {
|
||||
flexDirection: "row",
|
||||
@@ -567,16 +563,6 @@ const styles = StyleSheet.create({
|
||||
color: "rgba(255, 255, 255, 0.72)",
|
||||
textAlign: "center",
|
||||
},
|
||||
perksList: {
|
||||
gap: 6,
|
||||
alignItems: "center",
|
||||
},
|
||||
perkItem: {
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
fontSize: 13,
|
||||
color: "rgba(255, 255, 255, 0.72)",
|
||||
textAlign: "center",
|
||||
},
|
||||
priceBlock: {
|
||||
gap: 2,
|
||||
alignItems: "center",
|
||||
|
||||
Reference in New Issue
Block a user