Connect Ajou


๐Ÿ‘†Go to GitHub by clicking the image above!๐Ÿ‘†


What is this?
It is a mobile application project for international students at Ajou University and Korean students who want to join various exchange programs from Ajou University.


Tech Stack
React Native, Firebase


Organization
CONNECT_AJOU/
โ”œโ”€โ”€ App.js
โ”œโ”€โ”€ MainScreenF.js
โ”œโ”€โ”€ Utilities/
โ”‚ โ”œโ”€โ”€ Firebase.js
โ”‚ โ””โ”€โ”€ UserPermissions.js
โ”œโ”€โ”€ Pages/
โ”‚ โ”œโ”€โ”€ AlarmPage/
โ”‚ โ”‚ โ”œโ”€โ”€ Chat.js
โ”‚ โ”‚ โ”œโ”€โ”€ ChatList.js
โ”‚ โ”‚ โ”œโ”€โ”€ Message.js
โ”‚ โ”‚ โ””โ”€โ”€ Notification.js
โ”‚ โ”œโ”€โ”€ CommunityPage/
โ”‚ โ”‚ โ”œโ”€โ”€ subCommunityPage/
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ addWriting.js
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ searchWriting.js
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ seeWriting.js
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ showList.js
โ”‚ โ”‚ โ”œโ”€โ”€ FindFriend.js
โ”‚ โ”‚ โ”œโ”€โ”€ GetInfo.js
โ”‚ โ”‚ โ”œโ”€โ”€ schoolLife.js
โ”‚ โ”‚ โ””โ”€โ”€ showAll.js
โ”‚ โ”œโ”€โ”€ HomeTab/
โ”‚ โ”‚ โ”œโ”€โ”€ AddFavorites.js
โ”‚ โ”‚ โ””โ”€โ”€ HomeTabMain.js
โ”‚ โ””โ”€โ”€ TimetablePage/
โ”‚ โ”œโ”€โ”€ CourseItem.js
โ”‚ โ”œโ”€โ”€ PickCourses.js
โ”‚ โ””โ”€โ”€ Timetable.js
โ”œโ”€โ”€ Alarm.js
โ”œโ”€โ”€ CommunityMain.js
โ”œโ”€โ”€ handleCommunity.js
โ”œโ”€โ”€ handleHome.js
โ”œโ”€โ”€ HomeTabF.js
โ”œโ”€โ”€ Login.js
โ”œโ”€โ”€ Registration.js
โ”œโ”€โ”€ TimetableTab.js
โ””โ”€โ”€ User.js

1. App.js
  1. ๋””๋ฐ”์ด์Šค์— ๋”ฐ๋ผ ํฐํŠธ ์‚ฌ์ด์ฆˆ๊ฐ€ ๋ณ€๋™๋˜์ง€ ์•Š๋„๋ก ์„ค์ •

    Text.defaultProps = Text.defaultProps || {};
    Text.defaultProps.allowFontScaling = false;
    


  2. ํฐํŠธ ๋กœ๋“œ & ํ‘ธ์‹œ ์•Œ๋žŒ์€ ๋‹ค ๋น„๋™๊ธฐ๋กœ ๋™์ž‘

    async function registerForPushNotification() {
    let token;
    if (Constants.isDevice) {
        const { status: existingStatus } =
        await Notifications.getPermissionsAsync();
        let finalStatus = existingStatus;
        if (existingStatus !== "granted") {
        const { status } = await Notifications.requestPermissionsAsync();
        finalStatus = status;
        }
        if (finalStatus !== "granted") {
        alert("Failed to get push token for push notification!");
        return;
        }
        token = (await Notifications.getExpoPushTokenAsync()).data;
        console.log(token);
    } else {
        alert("Must use physical device for Push Notifications");
    }
    

    ์‹ค์ œ ๋””๋ฐ”์ด์Šค์ธ์ง€ ํ™•์ธ -> ํ˜„์žฌ ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธ -> ์—†์œผ๋ฉด ๊ถŒํ•œ ์š”์ฒญ -> ์ตœ์ข… ๊ถŒํ•œ ํ™•์ธ


  3. ์‹คํ–‰ ๋กœ์ง

    ํฐํŠธ๊ฐ€ ๋‹ค ๋กœ๋“œ๋˜์—ˆ๊ณ , ์œ ์ € ์ •๋ณด ๋กœ๋”ฉ์ด ๋๋‚˜๋ฉด ์œ ์ € ์ •๋ณด ์ฒดํฌ

    -> ์œ ์ €๊ฐ€ ์žˆ์œผ๋ฉด MainScreenF.js๋กœ ๋ฐ”๋กœ ๋„˜์–ด๊ฐ / ์œ ์ €๊ฐ€ ์—†์œผ๋ฉด Registration.js๋กœ ๋„˜์–ด๊ฐ


2. Registration.js
  1. ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ๊ฐ€์ž…

    firebase
       .auth()
       .createUserWithEmailAndPassword(email, password)
       .then((response) => {
         const uid = response.user.uid;
         const data = {
           email,
           fullName,
           picture,
           url,
           myCourses,
         };
    


  2. ์œ ์ € ๋ฐ์ดํ„ฐ ์ƒ์„ฑ

    ์ด๋ฉ”์ผ, ์„ฑ๋ช…, ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์—ฌ๋ถ€, ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์ฃผ์†Œ, ๋‚˜์˜ ์ˆ˜๊ฐ•๋ชฉ๋ก

    const usersRef = firebase.firestore().collection("users");
    usersRef
      .doc(email)
      .set(data)
      .then(() => {
        setReRendering(isReRendering + 1);
      })
      .catch((error) => {
        console.error("Error: ", error);
      });
    


    ์ปค๋ฎค๋‹ˆํ‹ฐ ์ฆ๊ฒจ์ฐพ๊ธฐ

    const favoritesRef = firebase.firestore().collection("favorites");
    favoritesRef.doc(email).set(
      {
        selectedItemsArray: [],
      },
      { merge: true }
    );
    
    allCommunities.forEach((element) => {
      favoritesRef
        .doc(email)
        .collection("all")
        .doc(element)
        .set({}, { merge: true });
    });
    
    favoritesRef.doc(email).collection("selectedItems").add({});
    

3. MainScreenF.js
  1. Bottom Tab Navigator

    • Pages/handleHome.js
    • Pages/CommunityMain.js
    • Pages/TimetableTab.js
    • Pages/Alarm.js
    • Pages/User.js


  2. ์œ ์ € ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

    const curUserEmail = firebase.auth().currentUser.providerData[0].email;
    const unsubscribe = firebase
      .firestore()
      .collection("users")
      .doc(curUserEmail)
      .onSnapshot((snapshot) => {
        const getUser = snapshot.data();
        setUser(getUser);
        if (!getUser.myCourses.length) {
          return () => {
            unsubscribe();
          };
        }
    


  3. ์ˆ˜๊ฐ•๋ชฉ๋ก ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

    getUser.myCourses.forEach((course) => {
      let background = randomHex();
      const courseRef = firebase.firestore().collection("courses").doc(course);
      courseRef.get().then((doc) => {
        const getMyCourse = doc.data();
        let array_of_schedules = splitSchedule(getMyCourse.schedule);
        for (var i = 0; i < array_of_schedules.length; i++) {
          let day = array_of_schedules[i].substr(0, 3);
          let time = array_of_schedules[i].substr(4, 1);
          let row = matchTime(time);
          let column = matchDays(day);
          if (isSelected[row][column] == "#FFFFFF") {
            isSelected[row][column] = background;
            courseName[row][column] = getMyCourse.name;
          }
        }
      });
    });
    

    ๋‚˜์˜ ์ˆ˜๊ฐ•๋ชฉ๋ก์— ํ•ด๋‹นํ•˜๋Š” ๊ณผ๋ชฉ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ -> ๊ณผ๋ชฉ ์Šค์ผ€์ฅด ํ™•์ธ -> ํ•ด๋‹นํ•˜๋Š” ์‹œ๊ฐ„ํ‘œ ๋ฐฐ์—ด์— ๋ฐฐ๊ฒฝ์ƒ‰ & ๊ณผ๋ชฉ๋ช… ์ง€์ •



4. handleHome.js
  1. Stack Navigator

    • Pages/HomeTabF.js
    • Pages/CommunityPage/subCommunityPage/showList.js
    • Pages/CommunityPage/subCommunityPage/addWriting.js
    • Pages/CommunityPage/subCommunityPage/searchWriting.js
    • Pages/CommunityPage/subCommunityPage/seeWriting.js

5. HomeTabF.js
  1. Stack Navigator

    • Pages/HomeTab/HomeTabMain.js
    • Pages/HomeTab/AddFavorites.js


  2. ์ฆ๊ฒจ์ฐพ๊ธฐ์— ์ถ”๊ฐ€๋œ ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

    const getSelectedItems = firebase
      .firestore()
      .collection("favorites")
      .doc(curUserEmail)
      .collection("selectedItems")
      .orderBy("createdAt", "desc")
      .onSnapshot((querySnapshot) => {
        const selectedItems = querySnapshot.docs.map((docSnapshot) => {
          const selectedItem = {
            _id: docSnapshot.id,
            ...docSnapshot.data(),
          };
          return selectedItem;
        });
        setSelectedItems(selectedItems);
      });
    



6. AddFavorites.js
  1. ์ฆ๊ฒจ์ฐพ๊ธฐ์™€ ๊ด€๋ จ๋œ ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

    • ์ฆ๊ฒจ์ฐพ๊ธฐ์— ์ถ”๊ฐ€๋œ ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ฐ์ดํ„ฐ: selectedItems
    • ์ฆ๊ฒจ์ฐพ๊ธฐ์— ์ถ”๊ฐ€๋œ ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ฐฐ์—ด: selectedItemsArray
    • ๋ชจ๋“  ์ปค๋ฎค๋‹ˆํ‹ฐ: allItems


  2. ์ฆ๊ฒจ์ฐพ๊ธฐ์— ์ถ”๊ฐ€ํ•  ์ปค๋ฎค๋‹ˆํ‹ฐ ์„ ํƒ

    const pick = (community) => {
      let tempSelectedItems = selectedItemsArray;
      const index = tempSelectedItems.indexOf(community._id);
      if (index > -1) {
        tempSelectedItems.splice(index, 1);
      } else {
        tempSelectedItems.push(community._id);
      }
      setSelectedItemsArray(tempSelectedItems);
      setReRendering(isReRendering + 1);
    };
    

    ์ด๋ฏธ ์ฒดํฌ๋˜์–ด ์žˆ๋‹ค๋ฉด ํ•ด์ œ / ์ฒดํฌํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์ฒดํฌ

    {
      selectedItemsArray.includes(item._id) ? (
        <MaterialIcons
          name="check-box"
          size={24}
          color="black"
          style={style.communityIcon}
        />
      ) : (
        <MaterialIcons
          name="check-box-outline-blank"
          size={24}
          color="black"
          style={style.communityIcon}
        />
      );
    }
    


  3. ์ฆ๊ฒจ์ฐพ๊ธฐ์— ์ถ”๊ฐ€

    selectedItemsArray.forEach((item) => {
      selectedItemsRef
        .doc(item)
        .set(
          {
            createdAt: new Date().getTime(),
          },
          { merge: true }
        )
        .catch(function (error) {
          console.error("Error: ", error);
        });
    });
    

    ์ถ”๊ฐ€ํ•œ ์‹œ๊ฐ๊ณผ ํ•จ๊ป˜ DB์— ์—…๋กœ๋“œ

    firebase
      .firestore()
      .collection("favorites")
      .doc(user.email)
      .set(
        {
          selectedItemsArray: selectedItemsArray,
        },
        { merge: true }
      )
      .catch(function (error) {
        console.error("Error: ", error);
      });
    



7. CommunityMain.js
  1. Stack Navigator

    • Pages/HandleCommunity.js
    • Pages/CommunityPage/subCommunityPage/showList.js
    • Pages/CommunityPage/subCommunityPage/addWriting.js
    • Pages/CommunityPage/subCommunityPage/searchWriting.js
    • Pages/CommunityPage/subCommunityPage/seeWriting.js


  2. ์ปค๋ฎค๋‹ˆํ‹ฐ ๋„ค๋น„๊ฒŒ์ด์…˜ ํ—ค๋” ์ด๋ฆ„ ์„ค์ •

    function getHeaderTitle(route) {
      const routeName = getFocusedRouteNameFromRoute(route) ?? "All";
    
      switch (routeName) {
        case "All":
          return "All";
        case "Info":
          return "Info";
        case "Campus":
          return "Campus";
        case "Friends":
          return "Friends";
      }
    }
    


    getFocusedRouteNameFromRoute(route)๋Š” ํ˜„์žฌ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋Š” route์˜ ์ด๋ฆ„์„ ๋ฐ˜ํ™˜

    -> ๋งŒ์•ฝ ์ด ๊ฐ’์ด null์ด๊ฑฐ๋‚˜ undefined์ด๋ฉด ์˜ค๋ฅธ์ชฝ ๊ฐ’ ๋ฐ˜ํ™˜



8. showList.js
  1. ๊ธ€ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ

    const getData = db.onSnapshot((querySnapshot) => {
      const writings = querySnapshot.docs.map((docSnapshot) => {
        const data = {
          _id: docSnapshot.id,
          ...docSnapshot.data(),
        };
        return data;
      });
      setWriting(writings);
    });
    


    ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด onSnapshot ์‚ฌ์šฉ

  2. ๊ธ€ ๋ชฉ๋ก ๋ณด์—ฌ์ฃผ๊ธฐ

    <ScrollView style={style.container}>
        {writing.map((writing) => (
          <TouchableOpacity
            onPress={() => {
              navigation.push("See", {
                extraData: user,
                data: writing,
                listName: listName,
              });
            }}
            key={writing._id}
          >
            <Card style={style.box}>
    


    ๋ฐ์ดํ„ฐ๋ฅผ mapping ํ•ด์„œ ์Šคํฌ๋กค๋ทฐ์—์„œ ๋ณด์—ฌ์คŒ


9. addWriting.js
  1. ํ—ค๋” ์„ค์ •

    useLayoutEffect: ๋ Œ๋”๋ง ํ›„ ํ™”๋ฉด์ด ์—…๋ฐ์ดํŠธ ๋˜๊ธฐ ์ „์— ๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰(cf. useEffect๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰)

  2. ๊ธ€ ์ž‘์„ฑ

    const onSubmit = async (event) => {
      firebase
        .firestore()
        .collection(listName)
        .doc(title)
        .set({
          _id: Math.random().toString(36).slice(2),
          title: title,
          content: content,
          creator: user,
          createdAt: Date.now(),
          like: [],
          comments: [],
        })
        .then(() => {
          navigation.goBack();
        });
      setTitle("");
      setContent("");
    };
    



10. searchWriting.js
  1. ๊ฒ€์ƒ‰ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ

    const fetchWriting = () => {
      if (writing) {
        setWriting([]);
      }
      listRf
        .where("title", "<=", search)
        .get()
        .then((querySnapshot) => {
          querySnapshot.forEach((doc) => {
            const data = doc.data();
            setWriting((prev) => [data, ...prev]);
          });
        });
    
      setisSearch(false);
    };
    


  2. ๊ฒ€์ƒ‰ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ

    <Right>
            <TouchableOpacity
              onPress={() => {
                fetchWriting();
                setisSearch(true);
              }}
            >
              <Feather name="search" size={30} />
            </TouchableOpacity>
          </Right>
    };
    


    isSearch ๊ฐ’์ด true ์ด๋ฉด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ๋ณด์—ฌ์ง„๋‹ค.


11. seeWriting.js
  1. ์ข‹์•„์š” ํด๋ฆญ

  2. ๋Œ“๊ธ€ ์ž‘์„ฑ

  3. ๊ธ€ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ

    function getData() {
      const dbCom = firebase.firestore().collection(listName).doc(writing.title);
      dbCom.onSnapshot((doc) => {
        if (doc.data() !== undefined) {
          const data = doc.data().comments;
          setAllComment(data);
          const likeList = doc.data().like;
          setCurrentLike(likeList);
        }
      });
    }
    


    ๊ธ€์„ ์‚ญ์ œํ•˜๊ณ  ๋‚œ ํ›„์—๋Š” doc.data()๊ฐ€ undefined๊ฐ€ ๋˜๋ฏ€๋กœ if๋ฌธ์„ ์ถ”๊ฐ€ํ•˜์˜€๋‹ค.


  4. ๊ธ€ ์ˆ˜์ •

    const reWritingUpdate = () => {
      firebase
        .firestore()
        .collection(listName)
        .doc(writing.title)
        .get()
        .then((doc) => {
          firebase.firestore().collection(listName).doc(reTitle).set(
            {
              title: reTitle,
              content: reContent,
              comments: doc.data().comments,
              createdAt: doc.data().createdAt,
              creator: doc.data().creator,
              like: doc.data().like,
            },
            { merge: true }
          );
        });
      firebase.firestore().collection(listName).doc(writing.title).delete();
      setReModal(false);
      setModalVisible(false);
      navigation.goBack();
    };
    

    ๊ธ€ ์ œ๋ชฉ์ด ๋ฐ”๋€Œ๋ฏ€๋กœ ์›๋ž˜ ์กด์žฌํ•˜๋˜ doc์„ ์ง€์›Œ์ฃผ๊ณ  ์ƒˆ๋กœ์šด doc์„ ์ƒ์„ฑํ•˜์—ฌ์•ผ ํ•œ๋‹ค.
    <Modal>์•ˆ์— <Modal>์„ ๋˜ ๋„ฃ์–ด์ค˜์„œ ๊ธ€์„ ์ˆ˜์ •ํ•  ๋•Œ๋งŒ ํŒ์—…์ฐฝ์ด ๋ณด์ด๋„๋ก ํ•˜์˜€๋‹ค.


  5. ๊ธ€/๋Œ“๊ธ€ ์‚ญ์ œ

    onPress: () => {
                firebase
                  .firestore()
                  .collection(listName)
                  .doc(writing.title)
                  .update({
                    comments: firebase.firestore.FieldValue.arrayRemove(comment),
                  });
              },
    

    ๋Œ“๊ธ€ ์‚ญ์ œ ์‹œ, Firebase ๋ฐฐ์—ด ์š”์†Œ ์—…๋ฐ์ดํŠธ ์ฐธ๊ณ 


  6. ๊ธ€ ์ž‘์„ฑ์ž์™€ ์ฑ„ํŒ… ์‹œ์ž‘

    • ๊ธ€ ์ž‘์„ฑ์ž๊ฐ€ ๋ณธ์ธ์ด ์•„๋‹Œ ๊ฒฝ์šฐ, ๊ธฐ์กด ์ฑ„ํŒ…๋ฐฉ์œผ๋กœ ์ด๋™(cf. ๋ณธ์ธ์ผ ๊ฒฝ์šฐ์—๋Š” ๋งˆ์ด ํŽ˜์ด์ง€๋กœ ์ด๋™)
    • ๋งŒ์•ฝ ๊ธฐ์กด ์ฑ„ํŒ…๋ฐฉ์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ƒˆ๋กœ์šด ์ฑ„ํŒ…๋ฐฉ ์ƒ์„ฑ

      if (
           Object.keys(thread).length === 0 &&
           thread.constructor === Object
         ) {
           thread = {
             latestMessage: {
               text: "",
               createdAt: new Date().getTime(),
             },
             name: commentAuthor.fullName,
             target: {
               email: commentAuthor.email,
             },
             user: user,
           };
      
           firebase
             .firestore()
             .collection("chat")
             .doc(commentAuthor.email)
             .set(thread, { merge: true });
      
           firebase
             .firestore()
             .collection("chat")
             .doc(commentAuthor.email)
             .collection("messages")
             .add({
               text: "Your chat room has been created.",
               createdAt: new Date().getTime(),
               system: true,
             });
      

12. TimetableTab.js
  1. Stack Navigator

    • Pages/TimetablePage/Timetable.js
    • Pages/TimetablePage/PickCourses.js

13. Timetable.js
  1. ์ „์ฒด ๊ฐ•์˜ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ

    setCourses(array)


  2. ๋‚ด๊ฐ€ ์ˆ˜๊ฐ•ํ•˜๋Š” ๊ฐ•์˜ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ

    setMyCourses(getUser.myCourses)


  3. ๊ฐ•์˜ ์‚ญ์ œ

    const handleClickCourse = (courseName, row, col) => {
      Alert.alert("Do you want to remove this course?", courseName, [
        {
          text: "No",
          onPress: () => console.log("No"),
        },
        {
          text: "Yes",
          onPress: () => {
            console.log("Yes");
            removeBackground(isSelected[row][col]);
            let selected_code = getCourseCode(courseName);
            update_array = myCourses.filter(
              (element) => element !== selected_code
            );
            userRef
              .set(
                {
                  myCourses: update_array,
                },
                { merge: true }
              )
              .catch(function (error) {
                console.error("Error: ", error);
              });
          },
          style: "destructive",
        },
      ]);
    };
    


    filter() ๋ฉ”์„œ๋“œ๋Š” ์ฃผ์–ด์ง„ ํ•จ์ˆ˜์˜ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•˜๋Š” ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋ชจ์•„ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.


  4. ์‹œ๊ฐ„ํ‘œ ํ‹€ ์ƒ์„ฑ

    <View> ํƒœ๊ทธ๋กœ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์—ˆ๋‹ค.


14. PickCourses.js
  1. ์ „์ฒด ๊ฐ•์˜ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ

    setCourses(array)


  2. ๋‚ด๊ฐ€ ์ˆ˜๊ฐ•ํ•˜๋Š” ๊ฐ•์˜ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ

    setMyCourses(getUser.myCourses)


  3. ๊ฐ•์˜ ์ถ”๊ฐ€

    const handlePickCourse = (schedule, code, name) => {
      console.log("handling");
      let array_of_schedules = splitSchedule(schedule);
      setBackground(randomHex());
      for (var i = 0; i < array_of_schedules.length; i++) {
        let day = array_of_schedules[i].substr(0, 3);
        let time = array_of_schedules[i].substr(4, 1);
        if (isSelected[matchTime(time)][matchDays(day)] != "#FFFFFF") {
          Alert.alert("Duplicate Entry");
          return;
        }
        isSelected[matchTime(time)][matchDays(day)] = background;
        courseName[matchTime(time)][matchDays(day)] = name;
      }
      let update_array = myCourses;
      update_array.push(code);
      userRef
        .set(
          {
            myCourses: update_array,
          },
          { merge: true }
        )
        .catch(function (error) {
          console.error("Error: ", error);
        });
    };
    
    • myCourses์—๋Š” ๊ณผ๋ชฉ ์ฝ”๋“œ๋กœ ์ €์žฅ๋œ๋‹ค.
    • ์‹œ๊ฐ„์ด ์ค‘๋ณต๋˜๋ฉด ์ถ”๊ฐ€๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค.


  4. ๊ฐ•์˜ ๋ชฉ๋ก ๋ณด์—ฌ์ฃผ๊ธฐ

    <ScrollView>
      {courses.map((course) => (
        <TouchableOpacity
          onPress={() =>
            handlePickCourse(course.schedule, course.code, course.name)
          }
          key={course.code}
        >
          <CourseItem
            name={course.name}
            prof={course.prof}
            schedule={course.schedule}
            credits={course.credits}
            code={course.code}
          />
        </TouchableOpacity>
      ))}
    </ScrollView>
    


    courses.map()์„ ์‚ฌ์šฉํ•ด์„œ CourseItem.js์˜ function์„ ๋ณด์—ฌ์ค€๋‹ค.


15. Alarm.js
  1. Material Top Tab Navigator

    • Pages/AlarmPage/Notification.js
    • Pages/AlarmPage/Message.js

16. Notification.js
  1. ๊ณต์ง€์‚ฌํ•ญ ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

    const unsubscribe = firebase
      .firestore()
      .collection("notification")
      .orderBy("createdAt", "desc")
      .onSnapshot((querySnapshot) => {
        if (querySnapshot.size) {
          const notices = querySnapshot.docs.map((docSnapshot) => {
            return {
              ...docSnapshot.data(),
            };
          });
          setData(notices);
        } else {
          console.log("No such document!");
        }
      });
    
    • ์ตœ๊ทผ์ˆœ์œผ๋กœ ์ •๋ ฌ


  2. ๊ณต์ง€์‚ฌํ•ญ ๋งํฌ ์—ฐ๊ฒฐ

    const noticeClick = async (item) => {
      Linking.canOpenURL(item.url).then((supported) => {
        if (supported) {
          Linking.openURL(item.url);
        } else {
          Linking.openURL(
            "https://www.ajou.ac.kr/oia/notice/notice.do?mode=list&srCategoryId=108&srSearchKey=&srSearchVal="
          );
        }
      });
    


  3. ๊ณต์ง€์‚ฌํ•ญ ๋ชฉ๋ก ๋ณด์—ฌ์ฃผ๊ธฐ

    return (
      <View style={style.container}>
        <FlatList
          data={data}
          renderItem={renderItem}
          keyExtractor={(item) => item.id.toString()}
          contentContainerStyle={style.list}
        />
      </View>
    );
    


    const renderItem = ({ item }) => {
      const isRead = item.isRead;
    
      return (
        <TouchableOpacity
          style={[style.box, isRead ? style.boxRead : style.boxUnRead]}
          onPress={() => noticeClick(item)}
        >
          <View style=>
            <Text style={style.title}>{item.title}</Text>
            <Text style={style.time}>{calculateTime(item.createdAt)}</Text>
          </View>
          <Text style={style.content}>{item.content}</Text>
        </TouchableOpacity>
      );
    };
    
    • <FlatList> ํƒœ๊ทธ์™€ renderItem() function์„ ์ด์šฉํ•œ๋‹ค.
    • key ๊ฐ’์€ ๋ฐ˜๋“œ์‹œ ๋ฌธ์ž์—ด ์ด์–ด์•ผ ํ•œ๋‹ค.

17. Message.js
  1. Stack Navigator

    • Pages/AlarmPage/ChatList.js
    • Pages/AlarmPage/Chat.js

18. ChatList.js
  1. ์ฑ„ํŒ… ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ

    const unsubscribe = firebase
      .firestore()
      .collection("chat")
      .orderBy("latestMessage.createdAt", "desc")
      .onSnapshot((snapshot) => {
        const threads = [];
        snapshot.docs.map((docSnapshot) => {
          if (
            docSnapshot.data().user.email == user.email ||
            docSnapshot.data().target.email == user.email
          ) {
            let thread = {
              _id: docSnapshot.data().target.email,
              ...docSnapshot.data(),
            };
            threads.push(thread);
          }
        });
    
        setThreads(threads);
        setReRendering(isReRendering + 1);
      });
    
    • ์ตœ๊ทผ์ˆœ์œผ๋กœ ์ •๋ ฌ
    • ๋‚ด๊ฐ€ ๋Œ€ํ™”๋ฅผ ์‹œ์ž‘ํ•œ ์ฑ„ํŒ…๋ฐฉ / ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๋‚˜์™€์˜ ๋Œ€ํ™”๋ฅผ ์‹œ์ž‘ํ•œ ์ฑ„ํŒ…๋ฐฉ์„ ๋ณด์—ฌ์ค€๋‹ค.
    • DOM ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•ด setReRendering(isReRendering + 1)์„ ์‹คํ–‰ํ•œ๋‹ค.
    • thread์˜ _id๋Š” target.email


  2. ์ฑ„ํŒ…๋ฐฉ์œผ๋กœ ์ด๋™

    const moveToChat = (item) => {
      navigation.navigate("Chat", { thread: item, user: user });
    };
    
    • <FlatList>๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฑ„ํŒ… ๋ชฉ๋ก์„ ๋ณด์—ฌ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— renderItem()์˜ item์„ thread์— ๋‹ด์•„ ํ™”๋ฉด์„ ์ด๋™ํ•œ๋‹ค.



19. Chat.js
  1. ์ฑ„ํŒ… ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ

    const unsubscribe = firebase
      .firestore()
      .collection("chat")
      .doc(thread._id)
      .collection("messages")
      .orderBy("createdAt", "desc")
      .onSnapshot((snapshot) => {
        const messages = snapshot.docs.map((docSnapshot) => {
          const data = {
            _id: docSnapshot.id,
            text: "",
            createdAt: new Date().getTime(),
            ...docSnapshot.data(),
          };
          if (!docSnapshot.data().system) {
            data.user = {
              ...docSnapshot.data().user,
              name: docSnapshot.data().user.fullName,
            };
          }
          return data;
        });
    
        setMessages(messages);
      });
    
  2. GiftedChat ์ด์šฉ

    return (
      <GiftedChat
        messages={messages}
        onSend={onSend}
        user=
        renderAvatar={null}
        showAvatarForEveryMessage={true}
        alwaysShowSend={true}
        renderBubble={renderBubble}
      />
    );
    
  3. ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ

    async function onSend(messages) {
      const text = messages[0].text;
    
      firebase
        .firestore()
        .collection("chat")
        .doc(thread._id)
        .collection("messages")
        .add({
          text,
          createdAt: new Date().getTime(),
          user: {
            _id: user.email,
            name: user.fullName,
          },
        });
    
      await firebase
        .firestore()
        .collection("chat")
        .doc(thread._id)
        .set(
          {
            latestMessage: {
              text,
              createdAt: new Date().getTime(),
            },
          },
          { merge: true }
        );
    }
    

    ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š” messages[0]์˜ text๊ฐ€ ๋ณด๋‚ด๋Š” ๋ฉ”์‹œ์ง€์ด๋‹ค.


20. User.js
  1. Storage์—์„œ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๊ฐ€์ ธ์˜ค๊ธฐ

    usersRef.get().then((doc) => {
      const getuser = doc.data();
      if (getuser.picture) {
        setPicture(true);
        const storageRef = firebase.storage().ref(`${user.email}`);
        storageRef
          .getDownloadURL()
          .then((url) => {
            setUrl(url);
          })
          .catch((error) => {
            console.error("Error updating document: ", error);
          });
      }
    });
    
  2. Storage์— ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์˜ฌ๋ฆฌ๊ธฐ

    const uploadImageToStorage = async (path, imageName) => {
      const response = await fetch(path);
      const blob = await response.blob();
      const ref = firebase.storage().ref().child(imageName);
      return ref.put(blob);
    };
    
  3. ์ด๋ฆ„์„ ์ต๋ช…์œผ๋กœ ๋ฐ”๊พธ๊ธฐ

  4. ์ด๋ฆ„ ๋ฐ”๊พธ๊ธฐ

  5. ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์ดˆ๊ธฐํ™”

    onPress: () => {
             console.log("Yes");
             setPicture(false);
             setUrl("");
             const storageRef = firebase.storage().ref(`${user.email}`);
             storageRef
               .delete()
               .then(() => {
                 console.log("Your profile has been reset");
               })
               .catch((error) => {
                 console.error("Error updating document: ", error);
               });
    
             usersRef
               .set({ picture: false, url: "" }, { merge: true })
               .then(() => {
                 console.log("Document successfully updated!");
                 setReRendering(isReRendering + 1);
               })
               .catch((error) => {
                 console.error("Error updating document: ", error);
               });
           },
    
    • ๋กœ์ปฌ ๋ณ€์ˆ˜ profile, url ์ดˆ๊ธฐํ™”
    • Storage ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™”
    • Firestore DB ์ดˆ๊ธฐํ™”
  6. ๋กœ๊ทธ์•„์›ƒ

    firebase
      .auth()
      .signOut()
      .then(() => {
        console.log("Sign-out successful");
        Update.reloadAsync();
      })
      .catch((error) => {
        console.log("Error: ", error);
      });
    

    ์•ฑ ์žฌ์‹คํ–‰