Open In App

Create a Event Countdown App with React Native

Last Updated : 23 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we will create an event countdown time application using React Native. The Eve­nt Countdown App is a mobile application develope­d with React Native. It enable­s users to effortlessly cre­ate and monitor countdown timers for differe­nt events.

By providing the e­vent title, sele­cting a category, and specifying the date­ and time, users can set up the­ir desired countdown. The app the­n showcases a timer that displays the re­maining time until the eve­nt starts. Once the specifie­d event time is re­ached, the timer will ce­ase counting down, allowing users to promptly remove­ the countdown if neede­d.

Preview of final output: Let us have a look at how the final output will look like.

Create-a-Event-Countdown-App-with-React-Native

Prerequisites:

Approach:

  • To manage state, we will use the useState­ and useEffect hooks and use them to maintain different variable­s. In the application, timers in the­ state are organized as an array of obje­cts where each timer object encompasse­s event details, cate­gory, target date and time, re­maining time.
  • The use­Effect hook dynamically updates the time­ remaining for timers based on the­ current time. It then configure­s interval timers to run these­ timers and marks them as inactive whe­n they reach zero.
  • The app utilize­s the react-native-modal library to display a modal for se­lecting categories and the­ react-native-modal-datetime­-picker for choosing dates. In addition, it provides brie­f messages to confirm successful cate­gory or date selections, which disappe­ar after a second.
  • Use­rs are able to easily cre­ate timers by specifying a title­, category, and date. To ensure­ accuracy, the addTimer function not only verifie­s the input but also calculates the re­maining time before appe­nding the new timer

Steps to Create React Native Application

Step 1: Create a React Native Application

npx create-expo-app EventCountdownApp

Step 2: ​Change the directory to the project folder

cd EventCountdownApp

Step 3: Install required dependences

npm install react-native-modal-datetime-picker
npm install react-native-modal

Project Structure

The updated dependencies in package.json file will look like below:

"dependencies": {
"react-native-paper": "4.9.2",
"@expo/vector-icons": "^13.0.0",
"react-native-modal-datetime-picker": "*",
"@react-native-community/datetimepicker": "6.7.3",
"react-native-modal": "*"
}

Example: In this example, we are using the above-explained approach to create the event countdown app.

  • App.js: This file imports all the components and renders them on the screen.
  • Style.js: This file adds styling to the application.

Javascript




import React, { useState, useEffect } from "react";
import {
    View,
    Text,
    TextInput,
    ScrollView,
    StyleSheet,
    TouchableOpacity,
} from "react-native";
import DateTimePickerModal from "react-native-modal-datetime-picker";
import Modal from "react-native-modal";
import { styles } from "./Style";
 
const categoryColors = {
    Meeting: "#0984e3",
    Birthday: "#00b894",
    Reminder: "#00cec9",
};
 
function App() {
    const [timers, setTimers] = useState([]);
    const [newTimerTitle, setNewTimerTitle] = useState("");
    const [newTimerCategory, setNewTimerCategory] = useState("");
    const [newTimerDateTime, setNewTimerDateTime] = useState("");
    const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
    const [timerRunning, setTimerRunning] = useState(false);
    const [selectedDate, setSelectedDate] = useState(new Date());
 
    const [isModalVisible, setModalVisible] = useState(false);
    const [selectedCategory, setSelectedCategory] = useState("");
 
    const [categorySelectedMessage, setCategorySelectedMessage] = useState("");
    const [dateSelectedMessage, setDateSelectedMessage] = useState("");
 
    useEffect(() => {
        const intervalIds = {};
 
        const updateTimers = () => {
            setTimers((prevTimers) =>
                prevTimers.map((timer) => {
                    const targetTime = new Date(timer.targetDateTime).getTime();
                    const currentTime = new Date().getTime();
                    const timeRemaining = Math.max(
                        Math.floor((targetTime - currentTime) / 1000),
                        0
                    );
 
                    if (timeRemaining === 0) {
                        clearInterval(intervalIds[timer.id]);
                        return { ...timer, isRunning: false, timeRemaining: 0 };
                    }
 
                    return { ...timer, timeRemaining };
                })
            );
        };
 
        timers.forEach((timer) => {
            if (timer.isRunning && timer.timeRemaining > 0 && timerRunning) {
                intervalIds[timer.id] = setInterval(updateTimers, 1000);
            }
        });
 
        return () => {
            Object.values(intervalIds).forEach((intervalId) =>
                clearInterval(intervalId)
            );
        };
    }, [timers, timerRunning]);
 
    const removeTimer = (timerId) => {
        setTimers((prevTimers) =>
            prevTimers.filter((timer) => timer.id !== timerId)
        );
    };
 
    const calculateTimeRemaining = (targetTime) => {
        const currentTime = new Date().getTime();
        const timeDifference = targetTime - currentTime;
        const secondsRemaining = Math.max(Math.floor(timeDifference / 1000), 0);
        return secondsRemaining;
    };
 
    const formatTimeRemaining = (seconds) => {
        const days = Math.floor(seconds / (3600 * 24));
        const hours = Math.floor((seconds % (3600 * 24)) / 3600);
        const minutes = Math.floor((seconds % 3600) / 60);
        const remainingSeconds = seconds % 60;
 
        return {
            days,
            hours,
            minutes,
            seconds: remainingSeconds,
        };
    };
 
    const showDatePicker = () => {
        setDatePickerVisibility(true);
    };
 
    const hideDatePicker = () => {
        setDatePickerVisibility(false);
    };
 
    const handleConfirm = (date) => {
        setSelectedDate(date);
        setNewTimerDateTime(date.toISOString());
        setDateSelectedMessage("Date has been selected successfully");
        hideDatePicker();
        setTimeout(() => {
            setDateSelectedMessage("");
        }, 1000);
    };
 
    const toggleModal = () => {
        setModalVisible(!isModalVisible);
    };
 
    const handleCategorySelection = (category) => {
        setSelectedCategory(category);
        setCategorySelectedMessage("Category has been selected successfully");
        setModalVisible(false);
        setTimeout(() => {
            setCategorySelectedMessage("");
        }, 1000);
    };
 
    const addTimer = () => {
        if (!newTimerTitle || !selectedCategory || !newTimerDateTime) return;
 
        const targetDateTime = new Date(newTimerDateTime).getTime();
 
        const newTimer = {
            id: timers.length + 1,
            category: selectedCategory,
            targetDateTime,
            timeRemaining: calculateTimeRemaining(targetDateTime),
            isRunning: true,
            title: newTimerTitle,
            showTitleInput: false,
        };
 
        setTimers([...timers, newTimer]);
        setNewTimerTitle("");
        setNewTimerCategory("");
        setNewTimerDateTime("");
        setTimerRunning(true);
    };
 
    return (
        <ScrollView style={styles.container}>
            <View style={styles.inputContainer}>
                <Text style={styles.heading}>Event Countdown Timer</Text>
                <TextInput
                    style={styles.input}
                    placeholder="Timer Title"
                    value={newTimerTitle}
                    onChangeText={(text) => setNewTimerTitle(text)}
                />
                <TouchableOpacity
                    style={styles.button}
                    onPress={toggleModal}
                    disabled={!newTimerTitle}
                >
                    <Text style={styles.buttonText}>Select Category</Text>
                </TouchableOpacity>
                <Modal isVisible={isModalVisible}>
                    <View style={styles.modalContainer}>
                        <Text style={styles.modalTitle}>Select a Category</Text>
                        <TouchableOpacity
                            style={styles.categoryButton}
                            onPress={() => handleCategorySelection("Meeting")}
                        >
                            <Text style={styles.buttonText}>Meeting</Text>
                        </TouchableOpacity>
                        <TouchableOpacity
                            style={styles.categoryButton}
                            onPress={() => handleCategorySelection("Birthday")}
                        >
                            <Text style={styles.buttonText}>Birthday</Text>
                        </TouchableOpacity>
                        <TouchableOpacity
                            style={styles.categoryButton}
                            onPress={() => handleCategorySelection("Reminder")}
                        >
                            <Text style={styles.buttonText}>Reminder</Text>
                        </TouchableOpacity>
                    </View>
                </Modal>
                <Text style={styles.messageText}>
                    {categorySelectedMessage}
                </Text>
                <TouchableOpacity
                    style={styles.button}
                    onPress={showDatePicker}
                    disabled={!newTimerTitle || !selectedCategory}
                >
                    <Text style={styles.buttonText}>Select Date</Text>
                </TouchableOpacity>
                <DateTimePickerModal
                    isVisible={isDatePickerVisible}
                    mode="datetime"
                    onConfirm={handleConfirm}
                    onCancel={hideDatePicker}
                />
                <Text style={styles.messageText}>{dateSelectedMessage}</Text>
                <TouchableOpacity
                    style={styles.button}
                    onPress={addTimer}
                    disabled={
                        !newTimerTitle || !selectedCategory || !newTimerDateTime
                    }
                >
                    <Text style={styles.buttonText}>Add Timer</Text>
                </TouchableOpacity>
            </View>
            <View style={styles.timersContainer}>
                {timers.map((timer) => {
                    const timeRemaining = formatTimeRemaining(
                        timer.timeRemaining
                    );
 
                    return (
                        <View
                            key={timer.id}
                            style={[
                                styles.card,
                                {
                                    backgroundColor:
                                        categoryColors[timer.category] ||
                                        "transparent",
                                },
                            ]}
                        >
                            <Text style={styles.cardTitle}>{timer.title}</Text>
                            <Text style={styles.cardCategory}>
                                {timer.category}
                            </Text>
                            <View style={styles.timerInfo}>
                                {timeRemaining.days > 0 && (
                                    <View style={styles.timeInfo}>
                                        <Text>
                                            <Text style={styles.timeValue}>
                                                {timeRemaining.days}
                                            </Text>{" "}
                                            days
                                        </Text>
                                    </View>
                                )}
                                <View style={styles.timeInfo}>
                                    <Text>
                                        <Text style={styles.timeValue}>
                                            {timeRemaining.hours}
                                        </Text>{" "}
                                        hours
                                    </Text>
                                </View>
                                <View style={styles.timeInfo}>
                                    <Text>
                                        <Text style={styles.timeValue}>
                                            {timeRemaining.minutes}
                                        </Text>{" "}
                                        minutes
                                    </Text>
                                </View>
                                <View style={styles.timeInfo}>
                                    <Text>
                                        <Text style={styles.timeValue}>
                                            {timeRemaining.seconds}
                                        </Text>{" "}
                                        seconds
                                    </Text>
                                </View>
                            </View>
                            <TouchableOpacity
                                style={styles.button}
                                onPress={() => removeTimer(timer.id)}
                                disabled={timer.timeRemaining <= 0}
                            >
                                <Text style={styles.buttonText}>Remove</Text>
                            </TouchableOpacity>
                        </View>
                    );
                })}
            </View>
        </ScrollView>
    );
}
 
export default App;


Javascript




import { StyleSheet } from "react-native";
 
const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    inputContainer: {
        margin: 20,
    },
    heading: {
        fontSize: 30,
        textAlign: "center",
        color: "#0984e3",
        margin: 20,
        fontWeight: "bold",
    },
    input: {
        height: 40,
        borderColor: "gray",
        borderWidth: 1,
        marginBottom: 10,
        borderRadius: 5,
        paddingLeft: 10,
    },
    timersContainer: {
        margin: 10,
        alignItems: "center",
    },
    card: {
        margin: 10,
        padding: 10,
        borderRadius: 10,
        shadowColor: "black",
        shadowOffset: { width: 0, height: 2 },
        shadowOpacity: 0.3,
        shadowRadius: 4,
        elevation: 5,
        backgroundColor: "white",
    },
    cardTitle: {
        fontSize: 25,
        color: "white",
        marginBottom: 5,
        fontWeight: "bold",
    },
    cardCategory: {
        fontSize: 20,
        color: "#2d3436",
        marginBottom: 5,
        fontWeight: "bold",
    },
    timerInfo: {
        flexDirection: "row",
        alignItems: "center",
    },
    timeInfo: {
        backgroundColor: "lightgray",
        borderRadius: 5,
        padding: 5,
        margin: 2,
    },
    timeValue: {
        fontWeight: "bold",
    },
    button: {
        backgroundColor: "#0984e3",
        padding: 10,
        borderRadius: 5,
        marginTop: 5,
        marginBottom: 10,
    },
    buttonText: {
        color: "white",
        textAlign: "center",
    },
    modalContainer: {
        backgroundColor: "white",
        padding: 20,
        borderRadius: 10,
        shadowColor: "black",
        shadowOffset: { width: 0, height: 2 },
        shadowOpacity: 1,
        shadowRadius: 4,
        elevation: 5,
    },
    modalTitle: {
        fontSize: 18,
        marginBottom: 10,
    },
    categoryButton: {
        backgroundColor: "#0984e3",
        padding: 10,
        borderRadius: 5,
        marginBottom: 10,
    },
    messageText: {
        color: "green",
        textAlign: "center",
        marginTop: 10,
    },
});
 
export { styles };


Steps to run the application:

Step 1: To run react native application use the following command:

npx expo start

Step 2: Depending on your Operating System, type the following command.

  • To run on Android:
npx react-native run-android
  • To run on iOS:
npx react-native run-ios

Output:
Create-a-Event-Countdown-App-with-React-Native



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads