• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

atlp-rwanda / vikings-ec-fe / 232f6db9-b6f6-42a1-9aa1-11e087e2c026

pending completion
232f6db9-b6f6-42a1-9aa1-11e087e2c026

Pull #31

circleci

munezeroolivierhugue
feat: tract orders
Pull Request #31: #184759929 Implement Tracking Orders

338 of 660 branches covered (51.21%)

Branch coverage included in aggregate %.

64 of 64 new or added lines in 9 files covered. (100.0%)

1442 of 1902 relevant lines covered (75.81%)

21.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.91
/src/components/Notification.jsx
1
import React, { useEffect } from 'react';
2
import { useSelector, useDispatch } from 'react-redux';
3
import { io } from 'socket.io-client';
4
import { addNotifications, fetchNotifications, markAllAsRead } from '../features/notifications/getNotificationSlice';
5
import { markAllNotifications } from '../features/notifications/markAllNotificationsSlice';
6
import NotificationRow from './NotificationRow';
7
import getUserInfo from '../utils/getUserInfo';
8
import { showSuccessMessage, showErrorMessage } from '../utils/toast';
9
import Loader from './Loader';
10

11
const Notifications = () => {
54✔
12
  const [totalNotifications, setTotalNotifications] = React.useState(0);
23✔
13
  const [isOpen, setIsOpen] = React.useState(false);
23✔
14
  const { isLoading: isLoadingMore, notifications, pagination } = useSelector((state) => state.notifications);
63✔
15
  const { isLoading } = useSelector((state) => state.markAllNotifications);
63✔
16
  const dispatch = useDispatch();
23✔
17

18
  const socket = io.connect(process.env.REACT_APP_BASE_URL);
23✔
19
  const userInfo = getUserInfo();
23✔
20

21
  useEffect(() => {
23✔
22
    dispatch(fetchNotifications());
12✔
23
    socket.on(`notification.${userInfo?.id}`, (data) => {
12✔
24
      dispatch(addNotifications(data));
×
25
      showSuccessMessage(`${data?.message}`);
×
26
    });
27
  }, []);
28

29
  useEffect(() => {
23✔
30
    if (notifications) {
13!
31
      const unRead = notifications.filter(notification => notification.isRead === false);
21✔
32
      const notificationsCount = unRead.length;
13✔
33
      setTotalNotifications(notificationsCount);
13✔
34
    }
35
  }, [notifications]);
36

37
  const handleMarkAll = async () => {
23✔
38
    try {
1✔
39
      const response = await dispatch(markAllNotifications()).unwrap();
1✔
40
      showSuccessMessage(response?.message);
×
41
      dispatch(markAllAsRead());
×
42
    } catch (error) {
43
      showErrorMessage(error.data?.message);
×
44
    }
45
  }
46

47
  const handleLoadMore = () => {
23✔
48
    const currentPage = parseInt(pagination.currentPage);
1✔
49
    if(currentPage === pagination.totalPages) {
1!
50
      return false;
×
51
    }
52
    dispatch(fetchNotifications({ page: currentPage + 1, append: true }));
1✔
53
  }
54

55
  return (
23✔
56
    <>
57
      <div data-testid="notifications-list" className="relative font-bold flex justify-start items-start cursor-pointer" onClick={() => setIsOpen((isOpen) => !isOpen)}>
3✔
58
        { totalNotifications === 0 && <span className="absolute top-0 -right-1 bg-[#7AC751] text-white text-xs  px-1 rounded-full">
44✔
59
          {totalNotifications}
60
        </span>}
61
        { totalNotifications > 0 && <span className="absolute top-0 -right-1 bg-[#c75151] text-white text-xs  px-1 rounded-full">
25✔
62
          {totalNotifications}
63
        </span>}
64
        <span className="material-symbols-outlined text-[#7AC751] text-3xl">
65
          notifications
66
        </span>
67
      </div>
68
      <div className='shadow-2xl max-h-96 md:w-96 max-w-xs overflow-scroll rounded-xl absolute z-[9999999] bg-white md:top-28 md:right-36 top-20 right-9'>
69
        { isOpen && <><div className='flex justify-between items-center p-5'>
32✔
70
          <h2 className='text-xl font-extrabold text-[#266C00]'>
71
            Notifications
72
          </h2>
73
          { isLoading ? <span className='px-12 flex justify-center items-center'><Loader className="" /></span> : <div className='flex items-center border p-1 cursor-pointer' onClick={() => {handleMarkAll()}}>
1✔
74
            <p className='text-xs font-light text-[rgb(122,199,81)]'>
75
              Mark all as read
76
            </p>
77
            <span className="material-symbols-outlined text-[#7AC751] rounded-full">
78
              done_all
79
            </span>
80
          </div>}
81
        </div><hr className="h-0.5 mx-5 bg-gray-300" /></>}
82
        <div className='flex flex-col gap-3'>
83
          {isOpen && notifications?.map(notification => (
32✔
84
            <NotificationRow key={notification.id} {...notification} />
9✔
85
        ))}
86
        {isOpen && (isLoadingMore? <span className='px-12 flex justify-center items-center'><Loader className="" /></span> : <button
41✔
87
          className="self-center my-5 bg-green-500 px-2 py-1 rounded-full text-xs text-white mx-auto disabled:opacity-50 disabled:cursor-not-allowed"
88
          type="button"
89
          disabled={(parseInt(pagination.currentPage) === pagination.totalPages) || !notifications
4✔
90
          ?.length}
91
          onClick={handleLoadMore}
92
        >LOAD MORE</button>)}
93
        </div>
94
      </div>
95
    </>
96
  );
97
};
98

99
export default Notifications;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc