Skip to content

Commit

Permalink
Add NoticeView (#313)
Browse files Browse the repository at this point in the history
* Add `NoticeView`

* Apply SwiftFormat changes

* `notices` -> `notice`

---------

Co-authored-by: peng-u-0807 <[email protected]>
  • Loading branch information
peng-u-0807 and peng-u-0807 authored Sep 29, 2024
1 parent 5065f38 commit 2d8cfc4
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 12 deletions.
4 changes: 4 additions & 0 deletions SNUTT-2022/SNUTT.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
B8B22D1629311F6200AB88F3 /* EmptyLectureList.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B22D1529311F6200AB88F3 /* EmptyLectureList.swift */; };
B8B7501D2B6274A5004F6272 /* KakaoMapsSDK_SPM in Frameworks */ = {isa = PBXBuildFile; productRef = B8B7501C2B6274A5004F6272 /* KakaoMapsSDK_SPM */; };
B8BC0C9028BE02D2007A1CA8 /* ReviewRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BC0C8F28BE02D2007A1CA8 /* ReviewRepository.swift */; };
B8C4F3352CA8F48E006B6BAD /* NoticeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8C4F3342CA8F48E006B6BAD /* NoticeView.swift */; };
B8E51E6628B5EC500065248E /* NetworkConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8E51E6528B5EC500065248E /* NetworkConfiguration.swift */; };
B8E51E6828B615140065248E /* WebErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8E51E6728B615140065248E /* WebErrorView.swift */; };
B8E51E6B28B769680065248E /* ReviewRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8E51E6A28B769680065248E /* ReviewRouter.swift */; };
Expand Down Expand Up @@ -404,6 +405,7 @@
B8AF8D3D28C72A880056DE62 /* ValidationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidationUtils.swift; sourceTree = "<group>"; };
B8B22D1529311F6200AB88F3 /* EmptyLectureList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyLectureList.swift; sourceTree = "<group>"; };
B8BC0C8F28BE02D2007A1CA8 /* ReviewRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewRepository.swift; sourceTree = "<group>"; };
B8C4F3342CA8F48E006B6BAD /* NoticeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeView.swift; sourceTree = "<group>"; };
B8E51E5C28B546770065248E /* DebugConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DebugConfig.xcconfig; sourceTree = "<group>"; };
B8E51E5E28B547000065248E /* ReleaseConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ReleaseConfig.xcconfig; sourceTree = "<group>"; };
B8E51E6528B5EC500065248E /* NetworkConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkConfiguration.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1140,6 +1142,7 @@
B82EA54B2B62C8490029FDF3 /* LectureMapView.swift */,
B82EA54D2B6393190029FDF3 /* KakaoMapView.swift */,
B8E65A732B4D4E3900BE4930 /* TimeRangeSelectionSheet.swift */,
B8C4F3342CA8F48E006B6BAD /* NoticeView.swift */,
);
path = Components;
sourceTree = "<group>";
Expand Down Expand Up @@ -1521,6 +1524,7 @@
BED04D2F28EA6FA600937E4C /* SettingsMenuItem.swift in Sources */,
738406FF2B5718C600007E62 /* ThemeDetailViewModel.swift in Sources */,
B8B22D1629311F6200AB88F3 /* EmptyLectureList.swift in Sources */,
B8C4F3352CA8F48E006B6BAD /* NoticeView.swift in Sources */,
BE28036228E884F400B2B1AB /* ReviewWebView.swift in Sources */,
BEB3B6A528CDE1FD00E56062 /* TimeUtils.swift in Sources */,
BE2CB3632959C0CC00FCF0F0 /* ReviewState.swift in Sources */,
Expand Down
4 changes: 2 additions & 2 deletions SNUTT-2022/SNUTT/AppState/AppEnvironment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,12 @@ extension EnvironmentValues {

#if DEBUG
extension AppEnvironment.Services {
@MainActor static func preview(appState: AppState) -> Self {
@MainActor static func preview(appState _: AppState) -> Self {
.init(timetableService: FakeTimetableService(),
userService: FakeUserService(),
lectureService: FakeLectureService(),
searchService: FakeSearchService(),
globalUIService: GlobalUIService(appState: appState, localRepositories: .init(userDefaultsRepository: UserDefaultsRepository(storage: .preview)), webRepositories: nil),
globalUIService: FakeGlobalUIService(),
courseBookService: FakeCourseBookService(),
authService: FakeAuthService(),
notificationService: FakeNotificationService(),
Expand Down
2 changes: 2 additions & 0 deletions SNUTT-2022/SNUTT/AppState/States/SystemState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class SystemState {

@Published var selectedTab: TabType = .timetable

@Published var noticeViewInfo: ConfigsDto.NoticeViewInfoDto?

var isMapViewExpanded: Bool?
var configs: ConfigsDto?
}
7 changes: 7 additions & 0 deletions SNUTT-2022/SNUTT/Repositories/Dto/ConfigDto.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct ConfigsDto: Codable {
let vacancySugangSnuUrl: VacancySugangSnuUrlDto?
let settingsBadge: SettingsBadgeDto?
let reactNativeBundleFriends: ReactNativeBundleFriendsDto?
let notice: NoticeViewInfoDto?
let disableMapFeature: Bool?
}

Expand All @@ -35,4 +36,10 @@ extension ConfigsDto {
src["ios"]
}
}

struct NoticeViewInfoDto: Codable {
let title: String
let content: String
let visible: Bool
}
}
55 changes: 52 additions & 3 deletions SNUTT-2022/SNUTT/Services/GlobalUIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,17 @@ protocol GlobalUIServiceProtocol: Sendable {

func setRoutingState<V>(_ key: WritableKeyPath<ViewRoutingState, V>, value: V)
func hasNewBadge(settingName: String) -> Bool

func showNoticeViewIfNeeded() async throws
}

struct GlobalUIService: GlobalUIServiceProtocol, UserAuthHandler {
struct GlobalUIService: GlobalUIServiceProtocol, UserAuthHandler, ConfigsProvidable {
var appState: AppState
var localRepositories: AppEnvironment.LocalRepositories
var webRepositories: AppEnvironment.WebRepositories?
var webRepositories: AppEnvironment.WebRepositories

var configRepository: ConfigRepositoryProtocol? {
webRepositories?.configRepository
webRepositories.configRepository
}

func setColorScheme(_ colorScheme: ColorScheme?) {
Expand Down Expand Up @@ -163,6 +165,13 @@ struct GlobalUIService: GlobalUIServiceProtocol, UserAuthHandler {
appState.menu.isLectureTimeSheetOpen = value
}

// MARK: Show Notice View

func showNoticeViewIfNeeded() async throws {
let configs = try await configRepository?.fetchConfigs()
appState.system.noticeViewInfo = configs?.notice
}

// MARK: Error Handling

func presentErrorAlert(error: Error) {
Expand Down Expand Up @@ -195,3 +204,43 @@ extension GlobalUIService {
appState.routing[keyPath: key] = value
}
}

class FakeGlobalUIService: GlobalUIServiceProtocol {
func setColorScheme(_: ColorScheme?) {}
func loadColorSchemeDuringBootstrap() {}

func setSelectedTab(_: TabType) {}
func setIsErrorAlertPresented(_: Bool) {}
func setIsMenuOpen(_: Bool) {}

func openEllipsis(for _: TimetableMetadata) {}
func closeEllipsis() {}

func openThemeSheet() {}
func closeThemeSheet() {}

func openRenameSheet() {}
func closeRenameSheet() {}

func openCreateSheet(withPicker _: Bool) {}
func closeCreateSheet() {}

func setRenameTitle(_: String) {}
func setCreateTitle(_: String) {}
func setCreateQuarter(_: Quarter?) {}

func setIsLectureTimeSheetOpen(_: Bool, modifying _: TimePlace?, action _: ((TimePlace) -> Void)?) {}

func presentErrorAlert(error _: STError?) {}
func presentErrorAlert(error _: ErrorCode) {}
func presentErrorAlert(error _: Error) {}

func preloadWebViews() {}
func sendMainWebViewReloadSignal() {}
func sendDetailWebViewReloadSignal(url _: URL) {}

func setRoutingState<V>(_: WritableKeyPath<ViewRoutingState, V>, value _: V) {}
func hasNewBadge(settingName _: String) -> Bool { return true }

func showNoticeViewIfNeeded() async throws {}
}
53 changes: 53 additions & 0 deletions SNUTT-2022/SNUTT/Views/Components/NoticeView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// NoticeView.swift
// SNUTT
//
// Created by 최유림 on 9/29/24.
//

import SwiftUI

struct NoticeView: View {
let title: String?
let content: String?
let sendFeedback: (String, String) async -> Bool

@State private var pushToFeedBackView = false

var body: some View {
VStack(spacing: 32) {
Image("warning.cat")
VStack(spacing: 8) {
if let title = title {
Text(title)
.font(STFont.title.font)
}
if let content = content {
Text(content)
.font(STFont.detailLabel.font)
.multilineTextAlignment(.center)
}
Spacer().frame(height: 4)
Button {
pushToFeedBackView = true
} label: {
Text("문의사항 보내기")
.foregroundColor(.white)
.font(.system(size: 14, weight: .semibold))
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(
STColor.cyan
)
.clipShape(.capsule)
}
}
}
.padding(.horizontal, 48)
.background(
NavigationLink("", isActive: $pushToFeedBackView) {
UserSupportView(email: nil, sendFeedback: sendFeedback)
}
)
}
}
45 changes: 38 additions & 7 deletions SNUTT-2022/SNUTT/Views/SNUTTView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ struct SNUTTView: View, Sendable {

var body: some View {
ZStack {
if viewModel.isAuthenticated && pushToTimetableScene {
if let noticeViewInfo = viewModel.noticeViewInfo, noticeViewInfo.visible {
NavigationView {
NoticeView(title: noticeViewInfo.title,
content: noticeViewInfo.content,
sendFeedback: viewModel.sendFeedback)
}
} else if viewModel.isAuthenticated && pushToTimetableScene {
TabView(selection: selected) {
TabScene(tabType: .timetable) {
TimetableScene(viewModel: .init(container: viewModel.container))
Expand Down Expand Up @@ -112,6 +118,9 @@ struct SNUTTView: View, Sendable {
setTabBarStyle()
setNavBarStyle()
}
.onLoad {
await viewModel.showNoticeViewIfNeeded()
}
let _ = debugChanges()
}

Expand All @@ -137,6 +146,7 @@ extension SNUTTView {
@Published var accessToken: String? = nil
@Published var preferredColorScheme: ColorScheme? = nil
@Published private var error: STError? = nil
@Published var noticeViewInfo: ConfigsDto.NoticeViewInfoDto?

@Published private var _isErrorAlertPresented = false
var isErrorAlertPresented: Bool {
Expand All @@ -162,6 +172,7 @@ extension SNUTTView {
appState.user.$accessToken.assign(to: &$accessToken)
appState.system.$preferredColorScheme.assign(to: &$preferredColorScheme)
appState.system.$selectedTab.assign(to: &$_selectedTab)
appState.system.$noticeViewInfo.assign(to: &$noticeViewInfo)
}

var errorTitle: String {
Expand All @@ -181,12 +192,10 @@ extension SNUTTView {
}

func getThemeList() async {
func getThemeList() async {
do {
try await services.themeService.getThemeList()
} catch {
services.globalUIService.presentErrorAlert(error: error)
}
do {
try await services.themeService.getThemeList()
} catch {
services.globalUIService.presentErrorAlert(error: error)
}
}

Expand Down Expand Up @@ -214,6 +223,14 @@ extension SNUTTView {
}
}

func showNoticeViewIfNeeded() async {
do {
try await services.globalUIService.showNoticeViewIfNeeded()
} catch {
services.globalUIService.presentErrorAlert(error: error)
}
}

func showVacancyBannerIfNeeded() async {
do {
try await services.vacancyService.showVacancyBannerIfNeeded()
Expand Down Expand Up @@ -257,6 +274,20 @@ extension SNUTTView {
services.globalUIService.presentErrorAlert(error: error)
}
}

func sendFeedback(email: String, message: String) async -> Bool {
if !Validation.check(email: email) {
services.globalUIService.presentErrorAlert(error: .INVALID_EMAIL)
return false
}
do {
try await services.etcService.sendFeedback(email: email, message: message)
return true
} catch {
services.globalUIService.presentErrorAlert(error: error)
return false
}
}
}
}

Expand Down

0 comments on commit 2d8cfc4

Please sign in to comment.