From 3721eee91991e0ab293912dc46fdd8389a2e10ed Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 8 Oct 2025 16:38:58 -0400 Subject: [PATCH 01/11] Refactored dummy data for networking prep. --- Resell/Models/Notification.swift | 40 +++++++++++++++++++ .../ViewModels/NotificationsViewModel.swift | 35 ++++------------ 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/Resell/Models/Notification.swift b/Resell/Models/Notification.swift index 8fc4380..154f856 100644 --- a/Resell/Models/Notification.swift +++ b/Resell/Models/Notification.swift @@ -13,9 +13,49 @@ struct Notifications: Codable { let body: String let data: NotificationData var isRead: Bool = false + let createdAt: Date + let updatedAt: Date } struct NotificationData: Codable { let type: String let messageId: String } + + +extension Notifications { + static let dummydata: [Notifications] = [ + Notifications( + userID: "381527oef-42b4-4fdd-b074-dfwbejko229", + title: "New Message", + body: "You have received a new message from Mateo", + data: NotificationData(type: "messages", messageId: "134841-42b4-4fdd-b074-jkfale"), + createdAt: Date(), + updatedAt: Date() + ), + Notifications( + userID: "381527oef-42b4-4fdd-b074-dfwbejko229", + title: "Request Received", + body: "You have a new request from Angelina", + data: NotificationData(type: "requests", messageId: "1"), + createdAt: Date(), + updatedAt: Date() + ), + Notifications( + userID: "381527oef-42b4-4fdd-b074-dfwbejko229", + title: "Bookmarked Item", + body: "Your bookmarked item is back in stock", + data: NotificationData(type: "bookmarks", messageId: "2"), + createdAt: Date(), + updatedAt: Date() + ), + Notifications( + userID: "381527oef-42b4-4fdd-b074-dfwbejko229", + title: "Order Update", + body: "Your listing has been bookmarked", + data: NotificationData(type: "your listings", messageId: "3"), + createdAt: Date(), + updatedAt: Date() + ) + ] +} diff --git a/Resell/ViewModels/NotificationsViewModel.swift b/Resell/ViewModels/NotificationsViewModel.swift index bfa29a4..1636238 100644 --- a/Resell/ViewModels/NotificationsViewModel.swift +++ b/Resell/ViewModels/NotificationsViewModel.swift @@ -23,32 +23,7 @@ class NotificationsViewModel: ObservableObject { "Your Listings": 5 ] - @Published var notifications: [Notifications] = [ - Notifications( - userID: "381527oef-42b4-4fdd-b074-dfwbejko229", - title: "New Message", - body: "You have received a new message from Mateo", - data: NotificationData(type: "messages", messageId: "134841-42b4-4fdd-b074-jkfale") - ), - Notifications( - userID: "381527oef-42b4-4fdd-b074-dfwbejko229", - title: "Request Received", - body: "You have a new request from Angelina", - data: NotificationData(type: "requests", messageId: "1") - ), - Notifications( - userID: "381527oef-42b4-4fdd-b074-dfwbejko229", - title: "Bookmarked Item", - body: "Your bookmarked item is back in stock", - data: NotificationData(type: "bookmarks", messageId: "2") - ), - Notifications( - userID: "381527oef-42b4-4fdd-b074-dfwbejko229", - title: "Order Update", - body: "Your listing has been bookmarked", - data: NotificationData(type: "your listings", messageId: "3") - ) - ] + @Published var notifications: [Notifications] = Notifications.dummydata var filteredNotifications: [Notifications] { if selectedTab == "All" { @@ -74,13 +49,17 @@ class NotificationsViewModel: ObservableObject { userID: "381527oef-42b4-4fdd-b074-dfwbejko229", title: "New Message", body: "You have received a new message from Mateo", - data: NotificationData(type: "messages", messageId: "12345") + data: NotificationData(type: "messages", messageId: "12345"), + createdAt: Date(), + updatedAt: Date() ), Notifications( userID: "381527oef-42b4-4fdd-b074-dfwbejko229", title: "New Request", body: "You have a new request from Angelina", - data: NotificationData(type: "requests", messageId: "23456") + data: NotificationData(type: "requests", messageId: "23456"), + createdAt: Date(), + updatedAt: Date() ) ] } From 8198728a125bb5427ed6c0a9fcf683639b6be435 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 8 Oct 2025 19:30:54 -0400 Subject: [PATCH 02/11] Implemented networking to fetch notifications. --- .DS_Store | Bin 10244 -> 10244 bytes Resell.xcodeproj/project.pbxproj | 24 +++++------------- Resell/.DS_Store | Bin 10244 -> 10244 bytes Resell/API/NetworkManager.swift | 8 ++++++ Resell/Models/Notification.swift | 4 +++ .../ViewModels/NotificationsViewModel.swift | 15 ++++++++++- Resell/Views/Home/NotificationsView.swift | 5 +++- 7 files changed, 36 insertions(+), 20 deletions(-) diff --git a/.DS_Store b/.DS_Store index 135b76d34b91ad7b3f3af6b64b5c400a106f2ab2..a0f0ca8d1a11ecec8e52cfffd784afe5f8819bb2 100644 GIT binary patch delta 82 zcmZn(XbIS`Tb!Bu>blAM#0@ywt)K30^FHnfFy73QX3OFlKbvoG1~+4^t}! SQ_H}>AixmBkjhXD#5n*!QypCZ delta 82 zcmZn(XbIS`Tb!B4>(%6a;szYQ{!d+3c>kCqkfSzPMuLkSDll1B!kBTx=0u4oewbP@ Tm|6w~1_6d3hE#@PAkF~*;d~)E diff --git a/Resell.xcodeproj/project.pbxproj b/Resell.xcodeproj/project.pbxproj index 9223a7d..32f2796 100644 --- a/Resell.xcodeproj/project.pbxproj +++ b/Resell.xcodeproj/project.pbxproj @@ -147,7 +147,7 @@ 2E8A5AAE2DBCD16500B1F281 /* FirebaseStorageCombine-Community in Frameworks */ = {isa = PBXBuildFile; productRef = 2E8A5AAD2DBCD16500B1F281 /* FirebaseStorageCombine-Community */; }; 2E8A5AB02DBCD16500B1F281 /* FirebaseVertexAI in Frameworks */ = {isa = PBXBuildFile; productRef = 2E8A5AAF2DBCD16500B1F281 /* FirebaseVertexAI */; }; 2E8A5AB12DBCD68200B1F281 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = D051D8162D7E2E0500C089AF /* GoogleService-Info.plist */; }; - 2E8A5AB22DBCD68700B1F281 /* resell-service.json in Resources */ = {isa = PBXBuildFile; fileRef = D0B4A25F2DA7184C00A1722C /* resell-service.json */; }; + 2E8A5AB22DBCD68700B1F281 /* (null) in Resources */ = {isa = PBXBuildFile; }; 2E8A5AB52DBD5B4300B1F281 /* SavedRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E8A5AB42DBD5B3200B1F281 /* SavedRow.swift */; }; 2E8C3D972DBD8A8B0074BFAB /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C1CE75D2CF6D04F00D38C25 /* NotificationsView.swift */; }; 2E8C3D992DBEE07B0074BFAB /* DetailedFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E8C3D982DBEE06E0074BFAB /* DetailedFilterView.swift */; }; @@ -155,23 +155,9 @@ 2EBB64182D8B783800CCAC48 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBB64172D8B783600CCAC48 /* Filter.swift */; }; 2ECB2F652E749ADD00CAACA2 /* ForYouView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ECB2F642E749AD900CAACA2 /* ForYouView.swift */; }; 2ECB2F672E74E03700CAACA2 /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ECB2F662E74E02F00CAACA2 /* SearchViewModel.swift */; }; - D037B9E62D7E308C00EF3024 /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = D037B9E52D7E308C00EF3024 /* FirebaseAnalytics */; }; - D037B9E82D7E308C00EF3024 /* FirebaseAnalyticsOnDeviceConversion in Frameworks */ = {isa = PBXBuildFile; productRef = D037B9E72D7E308C00EF3024 /* FirebaseAnalyticsOnDeviceConversion */; }; - D037B9EA2D7E308C00EF3024 /* FirebaseAnalyticsWithoutAdIdSupport in Frameworks */ = {isa = PBXBuildFile; productRef = D037B9E92D7E308C00EF3024 /* FirebaseAnalyticsWithoutAdIdSupport */; }; - D037B9EC2D7E308C00EF3024 /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = D037B9EB2D7E308C00EF3024 /* FirebaseAppCheck */; }; - D037B9EE2D7E308C00EF3024 /* FirebaseAppDistribution-Beta in Frameworks */ = {isa = PBXBuildFile; productRef = D037B9ED2D7E308C00EF3024 /* FirebaseAppDistribution-Beta */; }; - D037B9F02D7E313100EF3024 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = D037B9EF2D7E313100EF3024 /* FirebaseMessaging */; }; - D037B9F22D7E314D00EF3024 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = D037B9F12D7E314D00EF3024 /* FirebaseFirestore */; }; - D037B9F42D7E317700EF3024 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = D037B9F32D7E317700EF3024 /* FirebaseAuth */; }; - D043ED6D2D70CBEB00389DC1 /* GoogleSignIn in Frameworks */ = {isa = PBXBuildFile; productRef = D043ED6C2D70CBEB00389DC1 /* GoogleSignIn */; }; - D043ED6F2D70CBEB00389DC1 /* GoogleSignInSwift in Frameworks */ = {isa = PBXBuildFile; productRef = D043ED6E2D70CBEB00389DC1 /* GoogleSignInSwift */; }; + C6B37F592E970D7700A564DB /* FiltersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6B37F582E970D7700A564DB /* FiltersViewModel.swift */; }; D051D8172D7E2E0500C089AF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = D051D8162D7E2E0500C089AF /* GoogleService-Info.plist */; }; - D0961AF82D6E28D600DCC293 /* MessageDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0961AF72D6E28D300DCC293 /* MessageDocument.swift */; }; - D0961AFC2D6E42D500DCC293 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0961AFB2D6E42D100DCC293 /* Message.swift */; }; - D0961AFE2D6E47F500DCC293 /* Chat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0961AFD2D6E47F200DCC293 /* Chat.swift */; }; D0A25DEE2E5804A900607E1F /* EmptyStateModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A25DED2E5804A900607E1F /* EmptyStateModifier.swift */; }; - D0DAEF292D6F607300641151 /* MessageCluster.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DAEF282D6F606C00641151 /* MessageCluster.swift */; }; - D0DAEF2B2D6FF48800641151 /* MessagesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DAEF2A2D6FF47E00641151 /* MessagesViewModel.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -304,8 +290,8 @@ 2EBB64172D8B783600CCAC48 /* Filter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Filter.swift; sourceTree = ""; }; 2ECB2F642E749AD900CAACA2 /* ForYouView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForYouView.swift; sourceTree = ""; }; 2ECB2F662E74E02F00CAACA2 /* SearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewModel.swift; sourceTree = ""; }; + C6B37F582E970D7700A564DB /* FiltersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersViewModel.swift; sourceTree = ""; }; D051D8162D7E2E0500C089AF /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - D063A0182DBC268700F17A9C /* Untitled.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Untitled.swift; sourceTree = ""; }; D0961AF72D6E28D300DCC293 /* MessageDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageDocument.swift; sourceTree = ""; }; D0961AFB2D6E42D100DCC293 /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; D0961AFD2D6E47F200DCC293 /* Chat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Chat.swift; sourceTree = ""; }; @@ -652,6 +638,7 @@ 2C525B802CB1F195007D5B8E /* SendFeedbackViewModel.swift */, 2C18FFE92CA1E4C900564577 /* SettingsViewModel.swift */, 2C4DD97C2C98D45B0055D0AB /* SetupProfileViewModel.swift */, + C6B37F582E970D7700A564DB /* FiltersViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -857,7 +844,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2E8A5AB22DBCD68700B1F281 /* resell-service.json in Resources */, + 2E8A5AB22DBCD68700B1F281 /* (null) in Resources */, D051D8172D7E2E0500C089AF /* GoogleService-Info.plist in Resources */, 2C9EAF702CF26DA00010A44C /* Rubik-Regular.ttf in Resources */, 2C9B4D0C2C90EF1D0029DF61 /* Launch Screen.storyboard in Resources */, @@ -915,6 +902,7 @@ 2C9337542C935C9500818C8E /* ChatsView.swift in Sources */, 2E8A5AB52DBD5B4300B1F281 /* SavedRow.swift in Sources */, 2CD7CAB92CE937B10056209E /* Listing.swift in Sources */, + C6B37F592E970D7700A564DB /* FiltersViewModel.swift in Sources */, 2CD6CA8C2CB48286005A4F78 /* PopupModal.swift in Sources */, 2CF3561F2CDE93E00045A173 /* EditProfileViewModel.swift in Sources */, 2C02B3992CC040AE0020DF90 /* PriceInputView.swift in Sources */, diff --git a/Resell/.DS_Store b/Resell/.DS_Store index efa7d13bde0e0a19de1b44c97d67d65b548260ee..a9edb070d7f44bca4e06a4616273c768408a1a9c 100644 GIT binary patch delta 18 ZcmZn(XbITRF2%?=d4rV1<^@tIyZ}IT22TJ0 delta 18 ZcmZn(XbITRF2%?&d4rV1<^@tIyZ}IJ22KC~ diff --git a/Resell/API/NetworkManager.swift b/Resell/API/NetworkManager.swift index f4e4cb1..64a5422 100644 --- a/Resell/API/NetworkManager.swift +++ b/Resell/API/NetworkManager.swift @@ -480,13 +480,21 @@ class NetworkManager: APIClient { return try await post(url: url, body: image) } + // MARK: - Notifications Networking Functions + func getNotifications() async throws -> [Notifications] { + let url = try constructURL(endpoint: "/notif/recent/") + + return try await get(url: url) + } + // func createNotif(notifBody: Notification) async throws -> ListingResponse { // let url = try constructURL(endpoint: "/notif/") // // return try await post(url: url, body: notifBody) // } } + diff --git a/Resell/Models/Notification.swift b/Resell/Models/Notification.swift index 154f856..84d5361 100644 --- a/Resell/Models/Notification.swift +++ b/Resell/Models/Notification.swift @@ -22,6 +22,10 @@ struct NotificationData: Codable { let messageId: String } +struct NotifcationResponse: Codable { + let notifications: [Notifications] +} + extension Notifications { static let dummydata: [Notifications] = [ diff --git a/Resell/ViewModels/NotificationsViewModel.swift b/Resell/ViewModels/NotificationsViewModel.swift index 1636238..1be0a4b 100644 --- a/Resell/ViewModels/NotificationsViewModel.swift +++ b/Resell/ViewModels/NotificationsViewModel.swift @@ -41,9 +41,22 @@ class NotificationsViewModel: ObservableObject { notifications[index].isRead = true } } + + func fetchNotifications() { + Task { + do { + // MARK: - Check with backend to see if there are actually any notis + print(self.notifications) + self.notifications = try await NetworkManager.shared.getNotifications() + print(self.notifications) + } catch { + NetworkManager.shared.logger.error("Error in NotificationsViewModel.fetchNotifications: \(error)") + } + } + } /// Simulate fetching data - func fetchNotifications() { + func dummyFetchNotifications() { notifications = [ Notifications( userID: "381527oef-42b4-4fdd-b074-dfwbejko229", diff --git a/Resell/Views/Home/NotificationsView.swift b/Resell/Views/Home/NotificationsView.swift index 0bc35ea..1454463 100644 --- a/Resell/Views/Home/NotificationsView.swift +++ b/Resell/Views/Home/NotificationsView.swift @@ -34,6 +34,9 @@ struct NotificationsView: View { .padding(.top, 5) .padding(.vertical, 1) .navigationTitle("Notifications") + .onAppear { + viewModel.fetchNotifications() + } } // Creates the filter for notifications sorting @@ -65,7 +68,7 @@ struct NotificationsView: View { Spacer() notifText(for: notification) .font(.system(size: 14)) - Text("5 days ago") + Text("6 days ago") .font(.footnote) .foregroundColor(.gray) Spacer() From 793330daa123a087f9341e68294fef1bd198fa78 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 12 Oct 2025 14:34:13 -0400 Subject: [PATCH 03/11] Implemented notification filtering by date for sections. --- .DS_Store | Bin 10244 -> 10244 bytes Resell/Models/Notification.swift | 10 ++++--- .../ViewModels/NotificationsViewModel.swift | 25 ++++++++++++++++++ Resell/Views/Home/NotificationsView.swift | 23 ++++++++-------- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/.DS_Store b/.DS_Store index a0f0ca8d1a11ecec8e52cfffd784afe5f8819bb2..88102060dc5285dc5657370b777db439a4379081 100644 GIT binary patch delta 22 ccmZn(XbIS`N1W+~+~$4a|M-FQn+a diff --git a/Resell/Models/Notification.swift b/Resell/Models/Notification.swift index 84d5361..d7863b2 100644 --- a/Resell/Models/Notification.swift +++ b/Resell/Models/Notification.swift @@ -22,11 +22,15 @@ struct NotificationData: Codable { let messageId: String } -struct NotifcationResponse: Codable { - let notifications: [Notifications] +enum NotificationSection: String, CaseIterable, Identifiable { + case new = "New" + case last7 = "Last 7 Days" + case last30 = "Last 30 Days" + case older = "Older" + + var id: String {rawValue} } - extension Notifications { static let dummydata: [Notifications] = [ Notifications( diff --git a/Resell/ViewModels/NotificationsViewModel.swift b/Resell/ViewModels/NotificationsViewModel.swift index 1be0a4b..fd22160 100644 --- a/Resell/ViewModels/NotificationsViewModel.swift +++ b/Resell/ViewModels/NotificationsViewModel.swift @@ -32,6 +32,31 @@ class NotificationsViewModel: ObservableObject { return notifications.filter { $0.data.type.lowercased() == selectedTab.lowercased() } } } + + var groupedFilterNotifications: [NotificationSection: [Notifications]] { + let source = filteredNotifications + let now = Date() + let cal = Calendar.current + + var dict: [NotificationSection: [Notifications]] = [:] + + for noti in source { + let days = cal.dateComponents([.day], from: noti.createdAt, to: now).day ?? 0 + let section: NotificationSection + switch days { + case 0: section = .new + case 1...6: section = .last7 + case 7...29: section = .last30 + default: section = .older + } + dict[section, default: []].append(noti) + } + + for section in dict.keys { + dict[section]?.sort { $0.createdAt > $1.createdAt } + } + return dict + } // MARK: - Functions diff --git a/Resell/Views/Home/NotificationsView.swift b/Resell/Views/Home/NotificationsView.swift index 1454463..668406a 100644 --- a/Resell/Views/Home/NotificationsView.swift +++ b/Resell/Views/Home/NotificationsView.swift @@ -19,17 +19,18 @@ struct NotificationsView: View { VStack { filtersView .padding(.leading, 15) - Text("New") - .font(.headline) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.leading, 30) - .padding(.vertical, 10) - List(viewModel.filteredNotifications, id: \.data.messageId) { notification in - notificationView(for: notification) - .listRowInsets(EdgeInsets()) - .listRowSeparator(.hidden) - } - .listStyle(PlainListStyle()) +// Text("New") +// .font(.headline) +// .frame(maxWidth: .infinity, alignment: .leading) +// .padding(.leading, 30) +// .padding(.vertical, 10) +// List(viewModel.filteredNotifications, id: \.data.messageId) { notification in +// notificationView(for: notification) +// .listRowInsets(EdgeInsets()) +// .listRowSeparator(.hidden) +// } +// .listStyle(PlainListStyle()) + // MARK: - Implement displaying grouped filtered messages by section and real data. } .padding(.top, 5) .padding(.vertical, 1) From cb7da856f4e9f7acf71497e5278f210c645eeff4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 12 Oct 2025 17:45:45 -0400 Subject: [PATCH 04/11] Implemented view for date filtered Notis. --- Resell/Models/Notification.swift | 200 +++++++++++++++--- .../Contents.json | 21 ++ .../Message Round Icon from Figma.svg | 3 + .../read-notification.imageset/Contents.json | 2 +- .../mage_message-round.png | Bin 560 -> 0 bytes .../read-notification-dot.svg | 3 + .../ViewModels/NotificationsViewModel.swift | 2 +- Resell/Views/Home/NotificationsView.swift | 59 ++++-- 8 files changed, 236 insertions(+), 54 deletions(-) create mode 100644 Resell/Resources/Assets.xcassets/Message Round Icon from Figma.imageset/Contents.json create mode 100644 Resell/Resources/Assets.xcassets/Message Round Icon from Figma.imageset/Message Round Icon from Figma.svg delete mode 100644 Resell/Resources/Assets.xcassets/read-notification.imageset/mage_message-round.png create mode 100644 Resell/Resources/Assets.xcassets/read-notification.imageset/read-notification-dot.svg diff --git a/Resell/Models/Notification.swift b/Resell/Models/Notification.swift index d7863b2..0ee38cd 100644 --- a/Resell/Models/Notification.swift +++ b/Resell/Models/Notification.swift @@ -32,38 +32,170 @@ enum NotificationSection: String, CaseIterable, Identifiable { } extension Notifications { - static let dummydata: [Notifications] = [ - Notifications( - userID: "381527oef-42b4-4fdd-b074-dfwbejko229", - title: "New Message", - body: "You have received a new message from Mateo", - data: NotificationData(type: "messages", messageId: "134841-42b4-4fdd-b074-jkfale"), - createdAt: Date(), - updatedAt: Date() - ), - Notifications( - userID: "381527oef-42b4-4fdd-b074-dfwbejko229", - title: "Request Received", - body: "You have a new request from Angelina", - data: NotificationData(type: "requests", messageId: "1"), - createdAt: Date(), - updatedAt: Date() - ), - Notifications( - userID: "381527oef-42b4-4fdd-b074-dfwbejko229", - title: "Bookmarked Item", - body: "Your bookmarked item is back in stock", - data: NotificationData(type: "bookmarks", messageId: "2"), - createdAt: Date(), - updatedAt: Date() - ), - Notifications( - userID: "381527oef-42b4-4fdd-b074-dfwbejko229", - title: "Order Update", - body: "Your listing has been bookmarked", - data: NotificationData(type: "your listings", messageId: "3"), - createdAt: Date(), - updatedAt: Date() - ) - ] + static let dummydata: [Notifications] = { + let now = Date() + let cal = Calendar.current + + func hoursAgo(_ h: Int) -> Date { + now.addingTimeInterval(TimeInterval(-h * 3600)) + } + func daysAgo(_ d: Int) -> Date { + cal.date(byAdding: .day, value: -d, to: now)! + } + + return [ + // === New (same day, within 24h) === + Notifications( + userID: "user-mateo", + title: "New Message", + body: "You have received a new message from Mateo", + data: NotificationData(type: "message", messageId: "msg-0001"), + createdAt: hoursAgo(1), + updatedAt: hoursAgo(1) + ), + Notifications( + userID: "user-angelina", + title: "Request Received", + body: "You have a new request from Angelina", + data: NotificationData(type: "requests", messageId: "req-0001"), + createdAt: hoursAgo(5), + updatedAt: hoursAgo(5) + ), + Notifications( + userID: "user-lina", + title: "Bookmarked Item", + body: "Your bookmarked item is back in stock", + data: NotificationData(type: "bookmarks", messageId: "bm-0001"), + createdAt: hoursAgo(12), + updatedAt: hoursAgo(12) + ), + Notifications( + userID: "user-jay", + title: "Listing Activity", + body: "Your listing has been bookmarked", + data: NotificationData(type: "your listings", messageId: "yl-0001"), + createdAt: hoursAgo(20), + updatedAt: hoursAgo(20) + ), + + // === Last 7 Days (1–6 days) === + Notifications( + userID: "user-sam", + title: "New Message", + body: "Sam: Is this still available?", + data: NotificationData(type: "message", messageId: "msg-0002"), + createdAt: daysAgo(1), + updatedAt: daysAgo(1) + ), + Notifications( + userID: "user-zoe", + title: "Request Updated", + body: "Zoe updated her request", + data: NotificationData(type: "requests", messageId: "req-0002"), + createdAt: daysAgo(2), + updatedAt: daysAgo(2) + ), + Notifications( + userID: "user-rio", + title: "Discount Alert", + body: "An item you bookmarked was discounted", + data: NotificationData(type: "bookmarks", messageId: "bm-0002"), + createdAt: daysAgo(3), + updatedAt: daysAgo(3) + ), + Notifications( + userID: "user-noah", + title: "Listing Saved", + body: "Noah bookmarked your listing", + data: NotificationData(type: "your listings", messageId: "yl-0002"), + createdAt: daysAgo(4), + updatedAt: daysAgo(4) + ), + Notifications( + userID: "user-ivy", + title: "New Message", + body: "Ivy sent you a follow-up", + data: NotificationData(type: "message", messageId: "msg-0003"), + createdAt: daysAgo(6), + updatedAt: daysAgo(6) + ), + + // === Last 30 Days (7–29 days) === + Notifications( + userID: "user-ken", + title: "Request Accepted", + body: "Ken accepted your offer", + data: NotificationData(type: "requests", messageId: "req-0003"), + createdAt: daysAgo(7), + updatedAt: daysAgo(7) + ), + Notifications( + userID: "user-luca", + title: "Price Drop", + body: "Bookmarked item dropped in price", + data: NotificationData(type: "bookmarks", messageId: "bm-0003"), + createdAt: daysAgo(10), + updatedAt: daysAgo(10) + ), + Notifications( + userID: "user-mia", + title: "Listing Saved", + body: "Mia bookmarked your listing", + data: NotificationData(type: "your listings", messageId: "yl-0003"), + createdAt: daysAgo(15), + updatedAt: daysAgo(15) + ), + Notifications( + userID: "user-omar", + title: "New Message", + body: "Omar sent a question about size", + data: NotificationData(type: "message", messageId: "msg-0004"), + createdAt: daysAgo(20), + updatedAt: daysAgo(20) + ), + Notifications( + userID: "user-pia", + title: "Request Withdrawn", + body: "Pia withdrew a request", + data: NotificationData(type: "requests", messageId: "req-0004"), + createdAt: daysAgo(28), + updatedAt: daysAgo(28) + ), + + // === Older (30+ days) === + Notifications( + userID: "user-quinn", + title: "Old Message", + body: "Quinn asked about shipping", + data: NotificationData(type: "message", messageId: "msg-0005"), + createdAt: daysAgo(31), + updatedAt: daysAgo(31) + ), + Notifications( + userID: "user-ryan", + title: "Past Request", + body: "Ryan's request expired", + data: NotificationData(type: "requests", messageId: "req-0005"), + createdAt: daysAgo(45), + updatedAt: daysAgo(45) + ), + Notifications( + userID: "user-sara", + title: "Old Bookmark", + body: "Sara bookmarked a while ago", + data: NotificationData(type: "bookmarks", messageId: "bm-0004"), + createdAt: daysAgo(60), + updatedAt: daysAgo(60) + ), + Notifications( + userID: "user-tim", + title: "Older Listing Activity", + body: "Tim bookmarked your listing previously", + data: NotificationData(type: "your listings", messageId: "yl-0004"), + createdAt: daysAgo(120), + updatedAt: daysAgo(120) + ) + ] + }() } + diff --git a/Resell/Resources/Assets.xcassets/Message Round Icon from Figma.imageset/Contents.json b/Resell/Resources/Assets.xcassets/Message Round Icon from Figma.imageset/Contents.json new file mode 100644 index 0000000..abed00c --- /dev/null +++ b/Resell/Resources/Assets.xcassets/Message Round Icon from Figma.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Message Round Icon from Figma.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Resell/Resources/Assets.xcassets/Message Round Icon from Figma.imageset/Message Round Icon from Figma.svg b/Resell/Resources/Assets.xcassets/Message Round Icon from Figma.imageset/Message Round Icon from Figma.svg new file mode 100644 index 0000000..aa6c56d --- /dev/null +++ b/Resell/Resources/Assets.xcassets/Message Round Icon from Figma.imageset/Message Round Icon from Figma.svg @@ -0,0 +1,3 @@ + + + diff --git a/Resell/Resources/Assets.xcassets/read-notification.imageset/Contents.json b/Resell/Resources/Assets.xcassets/read-notification.imageset/Contents.json index 6d3f655..62cdc74 100644 --- a/Resell/Resources/Assets.xcassets/read-notification.imageset/Contents.json +++ b/Resell/Resources/Assets.xcassets/read-notification.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "mage_message-round.png", + "filename" : "read-notification-dot.svg", "idiom" : "universal", "scale" : "1x" }, diff --git a/Resell/Resources/Assets.xcassets/read-notification.imageset/mage_message-round.png b/Resell/Resources/Assets.xcassets/read-notification.imageset/mage_message-round.png deleted file mode 100644 index 5d8153fd264c92012c0f815c623f39c226af42bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 560 zcmV-00?+-4P)n4Q>fDvwj6BD#-P$r;E&~6ZH)dinvN^(u5li*2KezxLC#xd-# zv3P+Yh#SgxCP&+BQEuQg6X-m+L%kXTSD@K1Mdf0j1n%eias>4q-RWWGL+2u1=7h{c y#=@|@jZP;wL^qAoCz5vz{Q{D1o$5vQ_wWg9YX%oYg;+uW0000 + + diff --git a/Resell/ViewModels/NotificationsViewModel.swift b/Resell/ViewModels/NotificationsViewModel.swift index fd22160..e2ae11b 100644 --- a/Resell/ViewModels/NotificationsViewModel.swift +++ b/Resell/ViewModels/NotificationsViewModel.swift @@ -33,7 +33,7 @@ class NotificationsViewModel: ObservableObject { } } - var groupedFilterNotifications: [NotificationSection: [Notifications]] { + var groupedFilteredNotifications: [NotificationSection: [Notifications]] { let source = filteredNotifications let now = Date() let cal = Calendar.current diff --git a/Resell/Views/Home/NotificationsView.swift b/Resell/Views/Home/NotificationsView.swift index 668406a..cd23d6b 100644 --- a/Resell/Views/Home/NotificationsView.swift +++ b/Resell/Views/Home/NotificationsView.swift @@ -13,31 +13,52 @@ struct NotificationsView: View { @EnvironmentObject var router: Router @StateObject private var viewModel = NotificationsViewModel() + + private let relativeFormatter: RelativeDateTimeFormatter = { + let f = RelativeDateTimeFormatter() + f.unitsStyle = .full + return f + }() - + private func timeAgo(_ date: Date) -> String { + relativeFormatter.localizedString(for: date, relativeTo: Date()) + } + var body: some View { VStack { filtersView .padding(.leading, 15) -// Text("New") -// .font(.headline) -// .frame(maxWidth: .infinity, alignment: .leading) -// .padding(.leading, 30) -// .padding(.vertical, 10) -// List(viewModel.filteredNotifications, id: \.data.messageId) { notification in -// notificationView(for: notification) -// .listRowInsets(EdgeInsets()) -// .listRowSeparator(.hidden) -// } -// .listStyle(PlainListStyle()) - // MARK: - Implement displaying grouped filtered messages by section and real data. + .zIndex(1) + + List { + ForEach(NotificationSection.allCases) { section in + if let items = viewModel.groupedFilteredNotifications[section], !items.isEmpty { + Text(section.rawValue) + .font(.custom("Rubik-Medium", size: 18)) + .foregroundColor(.primary) + .fontWeight(.medium) + .textCase(nil) + .padding(.leading, 8) + .padding(.top, 5) + .listRowSeparator(.hidden) + ForEach(items, id: \.data.messageId) { notification in + notificationView(for: notification) + .listRowInsets(EdgeInsets()) + .listRowSeparator(.hidden) + } + } + } + } + .listStyle(.plain) + .listRowSeparator(.hidden) } .padding(.top, 5) .padding(.vertical, 1) .navigationTitle("Notifications") - .onAppear { - viewModel.fetchNotifications() - } + // MARK: - Uncomment when confirm notification data in backend +// .onAppear { +// viewModel.fetchNotifications() +// } } // Creates the filter for notifications sorting @@ -52,6 +73,7 @@ struct NotificationsView: View { } } .padding(.top, 20) + .padding(.bottom, 1) } .padding(.leading, 15) } @@ -69,7 +91,7 @@ struct NotificationsView: View { Spacer() notifText(for: notification) .font(.system(size: 14)) - Text("6 days ago") + Text(timeAgo(notification.createdAt)) .font(.footnote) .foregroundColor(.gray) Spacer() @@ -79,8 +101,9 @@ struct NotificationsView: View { } .padding(15) .padding(.horizontal, 15) + .contentShape(Rectangle()) .background(notification.isRead ? Color.white : Color.purple.opacity(0.1)) - .swipeActions(edge: .leading) { + .swipeActions(edge: .leading, allowsFullSwipe: true) { Button(action: { viewModel.markAsRead(notification: notification) }) { From a5c23e6e3643a526d20b29d47eb17051f36f39fa Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 13 Oct 2025 14:16:45 -0400 Subject: [PATCH 05/11] Fixed padding for notis. --- Resell/Views/Home/NotificationsView.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Resell/Views/Home/NotificationsView.swift b/Resell/Views/Home/NotificationsView.swift index cd23d6b..93487b9 100644 --- a/Resell/Views/Home/NotificationsView.swift +++ b/Resell/Views/Home/NotificationsView.swift @@ -96,11 +96,11 @@ struct NotificationsView: View { .foregroundColor(.gray) Spacer() } - .padding(.leading, 20) + .padding(.leading, 10) Spacer() } - .padding(15) - .padding(.horizontal, 15) + .padding(12) + .padding(.horizontal, 12) .contentShape(Rectangle()) .background(notification.isRead ? Color.white : Color.purple.opacity(0.1)) .swipeActions(edge: .leading, allowsFullSwipe: true) { From d96b5c7c225dba80cf80d125785fcaf9026981ec Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 21 Oct 2025 20:34:31 -0400 Subject: [PATCH 06/11] Implemented error handling and error screen for Notifications. --- Resell/Models/Notification.swift | 82 ++++++++++--------- .../ViewModels/NotificationsViewModel.swift | 30 +++++-- Resell/Views/Home/NotificationsView.swift | 69 ++++++++++++---- 3 files changed, 119 insertions(+), 62 deletions(-) diff --git a/Resell/Models/Notification.swift b/Resell/Models/Notification.swift index 0ee38cd..522076b 100644 --- a/Resell/Models/Notification.swift +++ b/Resell/Models/Notification.swift @@ -31,6 +31,14 @@ enum NotificationSection: String, CaseIterable, Identifiable { var id: String {rawValue} } +enum LoadState { + case idle + case loading + case success + case empty + case error +} + extension Notifications { static let dummydata: [Notifications] = { let now = Date() @@ -49,7 +57,7 @@ extension Notifications { userID: "user-mateo", title: "New Message", body: "You have received a new message from Mateo", - data: NotificationData(type: "message", messageId: "msg-0001"), + data: NotificationData(type: "messages", messageId: "msg-0001"), createdAt: hoursAgo(1), updatedAt: hoursAgo(1) ), @@ -69,21 +77,21 @@ extension Notifications { createdAt: hoursAgo(12), updatedAt: hoursAgo(12) ), - Notifications( - userID: "user-jay", - title: "Listing Activity", - body: "Your listing has been bookmarked", - data: NotificationData(type: "your listings", messageId: "yl-0001"), - createdAt: hoursAgo(20), - updatedAt: hoursAgo(20) - ), +// Notifications( +// userID: "user-jay", +// title: "Listing Activity", +// body: "Your listing has been bookmarked", +// data: NotificationData(type: "your listings", messageId: "yl-0001"), +// createdAt: hoursAgo(20), +// updatedAt: hoursAgo(20) +// ), // === Last 7 Days (1–6 days) === Notifications( userID: "user-sam", title: "New Message", body: "Sam: Is this still available?", - data: NotificationData(type: "message", messageId: "msg-0002"), + data: NotificationData(type: "messages", messageId: "msg-0002"), createdAt: daysAgo(1), updatedAt: daysAgo(1) ), @@ -103,19 +111,19 @@ extension Notifications { createdAt: daysAgo(3), updatedAt: daysAgo(3) ), - Notifications( - userID: "user-noah", - title: "Listing Saved", - body: "Noah bookmarked your listing", - data: NotificationData(type: "your listings", messageId: "yl-0002"), - createdAt: daysAgo(4), - updatedAt: daysAgo(4) - ), +// Notifications( +// userID: "user-noah", +// title: "Listing Saved", +// body: "Noah bookmarked your listing", +// data: NotificationData(type: "your listings", messageId: "yl-0002"), +// createdAt: daysAgo(4), +// updatedAt: daysAgo(4) +// ), Notifications( userID: "user-ivy", title: "New Message", body: "Ivy sent you a follow-up", - data: NotificationData(type: "message", messageId: "msg-0003"), + data: NotificationData(type: "messages", messageId: "msg-0003"), createdAt: daysAgo(6), updatedAt: daysAgo(6) ), @@ -137,19 +145,19 @@ extension Notifications { createdAt: daysAgo(10), updatedAt: daysAgo(10) ), - Notifications( - userID: "user-mia", - title: "Listing Saved", - body: "Mia bookmarked your listing", - data: NotificationData(type: "your listings", messageId: "yl-0003"), - createdAt: daysAgo(15), - updatedAt: daysAgo(15) - ), +// Notifications( +// userID: "user-mia", +// title: "Listing Saved", +// body: "Mia bookmarked your listing", +// data: NotificationData(type: "your listings", messageId: "yl-0003"), +// createdAt: daysAgo(15), +// updatedAt: daysAgo(15) +// ), Notifications( userID: "user-omar", title: "New Message", body: "Omar sent a question about size", - data: NotificationData(type: "message", messageId: "msg-0004"), + data: NotificationData(type: "messages", messageId: "msg-0004"), createdAt: daysAgo(20), updatedAt: daysAgo(20) ), @@ -167,7 +175,7 @@ extension Notifications { userID: "user-quinn", title: "Old Message", body: "Quinn asked about shipping", - data: NotificationData(type: "message", messageId: "msg-0005"), + data: NotificationData(type: "messages", messageId: "msg-0005"), createdAt: daysAgo(31), updatedAt: daysAgo(31) ), @@ -187,14 +195,14 @@ extension Notifications { createdAt: daysAgo(60), updatedAt: daysAgo(60) ), - Notifications( - userID: "user-tim", - title: "Older Listing Activity", - body: "Tim bookmarked your listing previously", - data: NotificationData(type: "your listings", messageId: "yl-0004"), - createdAt: daysAgo(120), - updatedAt: daysAgo(120) - ) +// Notifications( +// userID: "user-tim", +// title: "Older Listing Activity", +// body: "Tim bookmarked your listing previously", +// data: NotificationData(type: "your listings", messageId: "yl-0004"), +// createdAt: daysAgo(120), +// updatedAt: daysAgo(120) +// ) ] }() } diff --git a/Resell/ViewModels/NotificationsViewModel.swift b/Resell/ViewModels/NotificationsViewModel.swift index e2ae11b..1bc2e65 100644 --- a/Resell/ViewModels/NotificationsViewModel.swift +++ b/Resell/ViewModels/NotificationsViewModel.swift @@ -14,7 +14,11 @@ class NotificationsViewModel: ObservableObject { // MARK: - Properties - @Published var selectedTab: String = "All" + @Published var selectedTab: String = "All" { + didSet { recalcLoadState() } + } + + // MARK: - What is this for @Published var unreadNotifs: [String: Int] = [ "All": 10, "Messages": 2, @@ -23,14 +27,26 @@ class NotificationsViewModel: ObservableObject { "Your Listings": 5 ] - @Published var notifications: [Notifications] = Notifications.dummydata - + @Published var notifications: [Notifications] = Notifications.dummydata { + didSet { recalcLoadState() } + } + // MARK: - turn back to .idle when we use actual backend networking + @Published var loadState: LoadState = .success + var filteredNotifications: [Notifications] { if selectedTab == "All" { return notifications } else { - return notifications.filter { $0.data.type.lowercased() == selectedTab.lowercased() } + return notifications.filter { $0.data.type.lowercased() == selectedTab.lowercased() } } + } + + private func recalcLoadState() { + switch loadState { + case .loading, .error: + return + default: break } + loadState = filteredNotifications.isEmpty ? .empty : .success } var groupedFilteredNotifications: [NotificationSection: [Notifications]] { @@ -69,13 +85,13 @@ class NotificationsViewModel: ObservableObject { func fetchNotifications() { Task { + loadState = .loading do { // MARK: - Check with backend to see if there are actually any notis - print(self.notifications) self.notifications = try await NetworkManager.shared.getNotifications() - print(self.notifications) } catch { - NetworkManager.shared.logger.error("Error in NotificationsViewModel.fetchNotifications: \(error)") + NetworkManager.shared.logger.error("Error in NotificationsViewModel.fetchNotifications: \(error.localizedDescription)") + loadState = .error } } } diff --git a/Resell/Views/Home/NotificationsView.swift b/Resell/Views/Home/NotificationsView.swift index 93487b9..95c0330 100644 --- a/Resell/Views/Home/NotificationsView.swift +++ b/Resell/Views/Home/NotificationsView.swift @@ -29,28 +29,61 @@ struct NotificationsView: View { filtersView .padding(.leading, 15) .zIndex(1) - - List { - ForEach(NotificationSection.allCases) { section in - if let items = viewModel.groupedFilteredNotifications[section], !items.isEmpty { - Text(section.rawValue) - .font(.custom("Rubik-Medium", size: 18)) - .foregroundColor(.primary) - .fontWeight(.medium) - .textCase(nil) - .padding(.leading, 8) - .padding(.top, 5) - .listRowSeparator(.hidden) - ForEach(items, id: \.data.messageId) { notification in - notificationView(for: notification) - .listRowInsets(EdgeInsets()) + + switch viewModel.loadState { + case .idle: + ProgressView() + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + .offset(y: -60) + case .loading: + ProgressView() + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + .offset(y: -60) + case .success: + List { + ForEach(NotificationSection.allCases) { section in + if let items = viewModel.groupedFilteredNotifications[section], !items.isEmpty { + Text(section.rawValue) + .font(.custom("Rubik-Medium", size: 18)) + .foregroundColor(.primary) + .fontWeight(.medium) + .textCase(nil) + .padding(.leading, 8) + .padding(.top, 5) .listRowSeparator(.hidden) + ForEach(items, id: \.data.messageId) { notification in + notificationView(for: notification) + .listRowInsets(EdgeInsets()) + .listRowSeparator(.hidden) + } } } } + .listStyle(.plain) + .listRowSeparator(.hidden) + case .empty: + VStack (alignment: .center, spacing: 16) { + Text("You're all caught up!") + .font(.custom("Rubik-Medium", size: 22)) + .foregroundStyle(.black) + Text("No new notifications right now") + .font(.custom("Rubik", size: 18)) + .foregroundStyle(.gray) + } + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + .offset(y: -60) + case .error: + VStack (alignment: .center, spacing: 16) { + Text("Something went wrong!") + .font(.custom("Rubik-Medium", size: 22)) + .foregroundStyle(.black) + Text("Please try again. If this problem persists, feel free to let us know") + .font(.custom("Rubik", size: 18)) + .foregroundStyle(.gray) + } + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + .offset(y: -60) } - .listStyle(.plain) - .listRowSeparator(.hidden) } .padding(.top, 5) .padding(.vertical, 1) @@ -115,7 +148,7 @@ struct NotificationsView: View { private func notifText(for notification: Notifications) -> some View { switch notification.data.type { - case "message": + case "messages": return Text(notification.userID).bold() + Text(" sent you a message") case "requests": return Text("Your request for ") From 7a27a7f0f875548cc5fd07925696f43bd9fcc651 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 21 Oct 2025 21:07:03 -0400 Subject: [PATCH 07/11] Added small details to notification UI. --- .../bell.imageset/Bell Icon from Figma.svg | 5 +++++ .../bell.imageset/Contents.json | 2 +- .../Assets.xcassets/bell.imageset/bell.png | Bin 403 -> 0 bytes .../Contents.json | 21 ++++++++++++++++++ .../Ellipse 28 Resell FA25.png | Bin 0 -> 219 bytes Resell/Views/Home/HomeView.swift | 8 ++++++- Resell/Views/Home/NotificationsView.swift | 6 ++--- 7 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 Resell/Resources/Assets.xcassets/bell.imageset/Bell Icon from Figma.svg delete mode 100644 Resell/Resources/Assets.xcassets/bell.imageset/bell.png create mode 100644 Resell/Resources/Assets.xcassets/ellipse-notification.imageset/Contents.json create mode 100644 Resell/Resources/Assets.xcassets/ellipse-notification.imageset/Ellipse 28 Resell FA25.png diff --git a/Resell/Resources/Assets.xcassets/bell.imageset/Bell Icon from Figma.svg b/Resell/Resources/Assets.xcassets/bell.imageset/Bell Icon from Figma.svg new file mode 100644 index 0000000..73ea424 --- /dev/null +++ b/Resell/Resources/Assets.xcassets/bell.imageset/Bell Icon from Figma.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Resell/Resources/Assets.xcassets/bell.imageset/Contents.json b/Resell/Resources/Assets.xcassets/bell.imageset/Contents.json index e7387d0..f1e3ce4 100644 --- a/Resell/Resources/Assets.xcassets/bell.imageset/Contents.json +++ b/Resell/Resources/Assets.xcassets/bell.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "bell.png", + "filename" : "Bell Icon from Figma.svg", "idiom" : "universal", "scale" : "1x" }, diff --git a/Resell/Resources/Assets.xcassets/bell.imageset/bell.png b/Resell/Resources/Assets.xcassets/bell.imageset/bell.png deleted file mode 100644 index 6e2b3accb4b93c9c51faae79e9107e419a12fc0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 403 zcmV;E0c`$>P)b00009a7bBm000XU z000XU0RWnu7ytkO0drDELIAGL9O(c600d`2O+f$vv5yPJbmeomisR|=wsa0IFYX&pAnNI70lUFwKp2?SbTLb@7;`G@nHE1pL&~RFc=XxeHA}%rm4w$?c=Xe^p|AzHwwhG!fpkHAZlt}D z!`ob__5^>C0|A>EdQk_-i0k`sea=%m83OkW$DL9wDZ(+!E0Gox+$s` xji@&m8ymb&t53auk|3OvG(s_zTyj_VCm!^CW+r9r>VW_N002ovPDHLkV1l3Hp}_zE diff --git a/Resell/Resources/Assets.xcassets/ellipse-notification.imageset/Contents.json b/Resell/Resources/Assets.xcassets/ellipse-notification.imageset/Contents.json new file mode 100644 index 0000000..5e28e0a --- /dev/null +++ b/Resell/Resources/Assets.xcassets/ellipse-notification.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Ellipse 28 Resell FA25.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Resell/Resources/Assets.xcassets/ellipse-notification.imageset/Ellipse 28 Resell FA25.png b/Resell/Resources/Assets.xcassets/ellipse-notification.imageset/Ellipse 28 Resell FA25.png new file mode 100644 index 0000000000000000000000000000000000000000..64e4225613015c365947bfa98b331513ef517713 GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4aTa()7Bet#3xhBt!>l*8o|0J>k`30UXjv*C{y%QRF8x(k0qSX^w+>%(#3s}ty zMBFa$7BJs^pv&dKvoYpU%LMOVwToC9Jk=gNoDiA9bM-{K`|N;}N{c^_H}7yd&i5$l z($1rso$ow;6&WdAn%KH^%T Date: Tue, 21 Oct 2025 21:35:31 -0400 Subject: [PATCH 08/11] Changed to resellPurple constant color. --- Resell/Views/Home/NotificationsView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resell/Views/Home/NotificationsView.swift b/Resell/Views/Home/NotificationsView.swift index 400fe93..308fae8 100644 --- a/Resell/Views/Home/NotificationsView.swift +++ b/Resell/Views/Home/NotificationsView.swift @@ -134,14 +134,14 @@ struct NotificationsView: View { .padding(12) .padding(.horizontal, 12) .contentShape(Rectangle()) - .background(notification.isRead ? Color.white : Color(red: 0.62, green: 0.44, blue: 0.96).opacity(0.1)) + .background(notification.isRead ? Color.white : Constants.Colors.resellPurple.opacity(0.1)) .swipeActions(edge: .leading, allowsFullSwipe: true) { Button(action: { viewModel.markAsRead(notification: notification) }) { Image("read-notification") } - .tint(Color(red: 0.62, green: 0.44, blue: 0.96).opacity(0.7)) + .tint(Constants.Colors.resellPurple.opacity(0.7)) } } From d4e6af0fd49b7fb2cd440869d09f92e623d5b118 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 22 Oct 2025 17:39:03 -0400 Subject: [PATCH 09/11] Fixed text width for error screen. --- Resell/Views/Home/NotificationsView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resell/Views/Home/NotificationsView.swift b/Resell/Views/Home/NotificationsView.swift index 308fae8..751a0fe 100644 --- a/Resell/Views/Home/NotificationsView.swift +++ b/Resell/Views/Home/NotificationsView.swift @@ -80,7 +80,7 @@ struct NotificationsView: View { .font(.custom("Rubik", size: 18)) .foregroundStyle(.gray) } - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + .frame(maxWidth: 312, maxHeight: .infinity, alignment: .center) .offset(y: -60) } } From 33f9460abfbdea16189a58fa01080471005ae0eb Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 22 Oct 2025 18:11:27 -0400 Subject: [PATCH 10/11] Deleted comments. --- Resell/.DS_Store | Bin 10244 -> 10244 bytes Resell/Models/Notification.swift | 4 ---- 2 files changed, 4 deletions(-) diff --git a/Resell/.DS_Store b/Resell/.DS_Store index a9edb070d7f44bca4e06a4616273c768408a1a9c..b513c9b65583f164e4d6b8de7c93e9fe1f145b00 100644 GIT binary patch delta 45 xcmZn(XbIThBEZPF*;SyL5l9^r Date: Wed, 22 Oct 2025 18:13:36 -0400 Subject: [PATCH 11/11] Deleted comments. --- Resell/Models/Notification.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resell/Models/Notification.swift b/Resell/Models/Notification.swift index fec4079..de8dc78 100644 --- a/Resell/Models/Notification.swift +++ b/Resell/Models/Notification.swift @@ -6,7 +6,7 @@ // import Foundation -// Original name Notification overrides Foundation definition... + struct Notifications: Codable { let userID: String let title: String