Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Toasts not firing (help). #320

Open
milly-code opened this issue Oct 30, 2023 · 2 comments
Open

Toasts not firing (help). #320

milly-code opened this issue Oct 30, 2023 · 2 comments

Comments

@milly-code
Copy link

Whenever I import toast from "react-hot-toast/headless" and call toast('some message here'), I don't see a toast message.

Here's my code:

Sample.tsx where the toast function is used.

export const Sample = () => {
    const callToast = () => {
        toast("Message to be shown");
    }

    return (
        <View className="flex flex-1 h-full w-full items-center justify-center">
            <View className='w-1/2 mt-5'>
                <Button onPress={callToast}>Toast</Button>
            </View>
        </View>
    )
}

Notifications.tsx

import { useToaster } from "react-hot-toast/headless";

export const Notifications = () => {
    const { handlers, toasts } = useToaster();
    const { calculateOffset, updateHeight } = handlers;
    return (
        <View
            style={{
                position: 'absolute',
                top: 0,
                left: 0,
                right: 0,
            }}>

            {toasts.map((t) => {
                return (
                    <Toasty
                        key={t.id}
                        t={t}
                        updateHeight={(height) => updateHeight(t.id, height)}
                        offset={calculateOffset(t, { reverseOrder: false })}
                    />
                )
            }

            )}
        </View>
    );
};

Toasty.tsx

const Toasty = ({ t, updateHeight, offset }: { t: Toast, updateHeight: (val: number) => void, offset: number }) => {
    console.log("Toast added");
    // Animations for enter and exit
    const fadeAnim = useRef(new Animated.Value(t.type === 'custom' ? 1 : 0.5)).current;
    const posAnim = useRef(new Animated.Value(-120)).current;

    useEffect(() => {
        console.log("use effect")
        return Animated.timing(fadeAnim, {
            toValue: t.visible ? 1 : 0,
            duration: t.type === 'custom' ? 0 : 300,
            useNativeDriver: false
        }).start();
    }, [fadeAnim, t.type, t.visible]);

    useEffect(() => {
        console.log("use effect 2")
        return Animated.spring(posAnim, {
            toValue: t.visible ? offset : -120,
            useNativeDriver: false
        }).start();
    }, [posAnim, offset, t.visible]);

    return (
        <Animated.View
            className={t.type === 'custom' ? "items-center justify-center bg-dark/40 h-screen" : "mt-5"}
            style={{
                position: 'absolute',
                left: 0,
                right: 0,
                zIndex: t.visible ? 9999 : undefined,
                alignItems: 'center',
                opacity: fadeAnim,
                transform: [{ translateY: posAnim, },],
            }}>
            {
                t.type === 'custom' ?
                    (
                        <View
                            className={`${t.visible ? 'animate-enter' : 'animate-leave'} max-w-sm bg-white w-full shadow-2xl rounded-lg`}
                            style={{
                                shadowColor: "#5A5A5A",
                                shadowOpacity: 0.01,
                                elevation: 40,
                            }}
                            onLayout={(event) =>
                                updateHeight(event.nativeEvent.layout.height)
                            }
                        >

                            {t.message as ReactNode}
                        </View>
                    ) : (
                        <View
                            onLayout={(event) =>
                                updateHeight(event.nativeEvent.layout.height)
                            }
                            className={`${t.visible ? 'animate-enter' : 'animate-leave'} max-w-sm bg-white w-full shadow-2xl rounded-lg flex flex-row ring-1`}
                            style={{
                                shadowColor: "#5A5A5A",
                                shadowOpacity: 0.01,
                                elevation: 40,
                            }}
                        >
                            <View className="flex-1 w-0 p-4">
                                <View className="flex flex-row gap-x-5 items-center">
                                    <View className="flex-shrink-0 pt-0.5 mr">
                                        {
                                            t.type === "loading" ?
                                                <Spinner size={'small'} />
                                                : (
                                                    <View className={
                                                        `
                                                inline-flex items-center justify-center flex-shrink-0 w-8 h-8 rounded-lg
                                                ${t.type === 'success' ? 'bg-success' : t.type === 'error' ? 'bg-danger' : 'bg-blue-500'}
                                            `}>
                                                        <IonicIcons name={t.type === 'success' ? 'checkmark' : t.type === 'error' ? 'close' : 'information'} size={20} color={"#ffffff"} />
                                                    </View>
                                                )
                                        }

                                    </View>
                                    <View className="ml-3 flex-1">
                                        <Text className={`text-xs font-nunito-medium ${t.type === 'success' ? 'text-success' : t.type === 'error' ? 'text-danger' : 'text-blue-900'}`}>
                                            {
                                                t.type === 'success' ? 'Message' : t.type === 'error' ? 'Error' : t.type === "loading" ? "Loading" : 'Info'
                                            }
                                        </Text>
                                        <Text className="mt-1 text-sm font-nunito text-dark">
                                            {t.message as ReactNode}
                                        </Text>
                                    </View>
                                </View>
                            </View>
                            {
                                t.type === 'loading' ? null : (
                                    <View className="flex border-l border-gray-200 justify-center items-center">
                                        <TouchableOpacity onPress={() => toast.dismiss(t.id)}>
                                            <View className="w-full p-4 flex items-center justify-center">
                                                <IonicIcons name="close" size={20} color={"#ff0e0e"} />
                                            </View>
                                        </TouchableOpacity>
                                    </View>
                                )
                            }
                        </View>
                    )
            }
        </Animated.View>
    );
};

export default Toasty;

This is what my App.tsx looks like where I added the Notifications component

const AppRoot: FC = () => {
    activateKeepAwakeAsync();
    const { busy, fontsLoaded } = useOnAppStartup(fonts);

    const [queryClient] = useState(() => new QueryClient({ defaultOptions: { queries: { retry: 3 } } }));
    const authContext = useLoginContext({});
    if (!fontsLoaded || busy) {
        return <SplashScreen logo={<BickleLogo />} />;
    }

    return (
        <View className="flex flex-1">

            <QueryClientProvider client={queryClient}>
                <ApiProvider>
                    <AuthProvider context={authContext}>
                        <GestureHandlerRootView style={{ flex: 1 }}>
                            <BottomSheetModalProvider>
                                <StatusBarProvider>
                                    <NavigationContainer>
                                        <AppRouter />
                                    </NavigationContainer>
                                    <Notifications />
                                </StatusBarProvider>
                            </BottomSheetModalProvider>
                        </GestureHandlerRootView>
                    </AuthProvider>
                </ApiProvider>
            </QueryClientProvider>
        </View>
    );
};

Note

If I manually add a toast in the Notifications.tsx, it does render visible. See example below

export const Notifications = () => {
    const { handlers, toasts } = useToaster();
    const { calculateOffset, updateHeight } = handlers;
    const toastable: Toast = {
        type: 'error',
        id: '1000000',
        message: "Error message here",
        duration: 50000,
        pauseDuration: 3000,
        ariaProps: {
            role: "status",
            "aria-live": "assertive"
        },
        createdAt: Date.now(),
        visible: true,
    }
    return (
        <View
            style={{
                position: 'absolute',
                top: 0,
                left: 0,
                right: 0,
            }}>
                {/* manually added toast */}
            <Toasty
                key={'1000000'}
                t={toastable}
                updateHeight={(height) => updateHeight(toastable.id, height)}
                offset={calculateOffset(toastable, { reverseOrder: false })}
            />
            {toasts.map((t) => {
                return (
                    <Toasty
                        key={t.id}
                        t={t}
                        updateHeight={(height) => updateHeight(t.id, height)}
                        offset={calculateOffset(t, { reverseOrder: false })}
                    />
                )
            }

            )}
        </View>
    );
};
@timolins
Copy link
Owner

Hey! This might be related to updateHeight not being reported correctly. Can you double check if this gets called correctly?

@milly-code
Copy link
Author

Thanks for the quick reply @timolins
After debugging I noticed no toast object is being added to the toasts list in useToaster, so nothing is mapped for the updateHeight to be called.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants