Added codeable protocol to classes to deserialize API json objects 🔨

pull/23/head
Emre KARTAL 1 year ago
parent de12721408
commit 18a01ab349

@ -19,7 +19,7 @@ struct BetCard: View {
VStack(alignment: .leading,spacing: 2){ VStack(alignment: .leading,spacing: 2){
HStack{ HStack{
Spacer() Spacer()
Text("proposé par " + bet.author.username.capitalized) Text("proposé par " + bet.author.capitalized)
.font(.system(size: 10)) .font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
@ -82,7 +82,7 @@ struct BetCard_Previews: PreviewProvider {
isPublic: true, isPublic: true,
status: .inProgress, status: .inProgress,
invited: [], invited: [],
author: User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: []), author: "Imri",
registered: [])) registered: []))
.preferredColorScheme(.dark) .preferredColorScheme(.dark)
} }

@ -15,8 +15,8 @@ struct BetLineLoading: View {
var value: CGFloat { var value: CGFloat {
let totalParticipations = participations.count let totalParticipations = participations.count
let numberOfYes = participations.filter { $0.response.uppercased() == "YES" }.count let numberOfYes = participations.filter { $0.answer.uppercased() == "YES" }.count
let numberOfNo = participations.filter { $0.response.uppercased() == "NO" }.count let numberOfNo = participations.filter { $0.answer.uppercased() == "NO" }.count
if(numberOfNo == 0 && numberOfYes == 0){ if(numberOfNo == 0 && numberOfYes == 0){
return 0.5 return 0.5
} }
@ -25,11 +25,11 @@ struct BetLineLoading: View {
} }
var yesParticipations: [Participation] { var yesParticipations: [Participation] {
participations.filter { $0.response.uppercased() == "YES" } participations.filter { $0.answer.uppercased() == "YES" }
} }
var noParticipations: [Participation] { var noParticipations: [Participation] {
participations.filter { $0.response.uppercased() == "NO" } participations.filter { $0.answer.uppercased() == "NO" }
} }
var body: some View { var body: some View {

@ -1,5 +1,5 @@
// //
// ParticiationCell.swift // ParticipationCell.swift
// AllIn // AllIn
// //
// Created by Lucas Delanier on 21/01/2024. // Created by Lucas Delanier on 21/01/2024.
@ -8,20 +8,20 @@
import SwiftUI import SwiftUI
import Model import Model
struct ParticiationCell: View { struct ParticipationCell: View {
@State var participation: Participation? @State var participation: Participation
var body: some View { var body: some View {
HStack(alignment: .center, spacing: 0){ HStack(alignment: .center, spacing: 0){
Circle() Circle()
.frame(width: 30, height: 30) .frame(width: 30, height: 30)
.foregroundColor(AllInColors.grey700Color) .foregroundColor(AllInColors.grey700Color)
.padding(.trailing, 7) .padding(.trailing, 7)
Text(participation?.user.username ?? "Unknown") Text(participation.username)
.font(.system(size: 15)) .font(.system(size: 15))
.foregroundStyle(AllInColors.primaryTextColor) .foregroundStyle(AllInColors.primaryTextColor)
.fontWeight(.semibold) .fontWeight(.semibold)
Spacer() Spacer()
Text(participation?.stake.description ?? "NaN") Text(participation.stake.description)
.font(.system(size: 18)) .font(.system(size: 18))
.foregroundStyle(AllInColors.lightPurpleColor) .foregroundStyle(AllInColors.lightPurpleColor)
.fontWeight(.bold) .fontWeight(.bold)

@ -22,7 +22,7 @@ struct ReviewCard: View {
VStack(alignment: .leading,spacing: 2){ VStack(alignment: .leading,spacing: 2){
HStack{ HStack{
Spacer() Spacer()
Text("proposé par \(betDetail.bet.author.username)") Text("proposé par \(betDetail.bet.author)")
.font(.system(size: 10)) .font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
@ -44,7 +44,7 @@ struct ReviewCard: View {
VStack(alignment: .center,spacing:0){ VStack(alignment: .center,spacing:0){
HStack(){ HStack(){
Spacer() Spacer()
if(betDetail.bet.isFinish()){ if(betDetail.bet.endBetDate < Date()){
Text("Terminé") Text("Terminé")
.foregroundColor(.white) .foregroundColor(.white)
.font(.system(size: 25)) .font(.system(size: 25))
@ -72,7 +72,7 @@ struct ReviewCard: View {
.frame(width: .infinity) .frame(width: .infinity)
.padding(.all,2) .padding(.all,2)
.background( .background(
isAWin || betDetail.bet.isFinish() ? isAWin || betDetail.bet.endBetDate < Date() ?
AnyView(AllInColors.primaryGradient) : AnyView(AllInColors.primaryGradient) :
AnyView(Color.black) AnyView(Color.black)
) .cornerRadius(20, corners: [.bottomLeft,.bottomRight]) ) .cornerRadius(20, corners: [.bottomLeft,.bottomRight])

@ -110,14 +110,11 @@ class AuthService: IAuthService {
URLSession.shared.dataTask(with: request) { data, response, error in URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data, if let data = data,
let httpResponse = response as? HTTPURLResponse { let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 { if httpResponse.statusCode == 200, let user = try? JSONDecoder().decode(User.self, from: data) {
if let userJson = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let user = User.mapUser(from: userJson) {
AppStateContainer.shared.user = user AppStateContainer.shared.user = user
AppStateContainer.shared.loggedState.connectedUser = true AppStateContainer.shared.loggedState.connectedUser = true
WidgetCenter.shared.reloadAllTimelines() WidgetCenter.shared.reloadAllTimelines()
self.initManagerVM(token: token) self.initManagerVM(token: token)
}
} else { } else {
AppStateContainer.shared.authenticationRefresh = nil AppStateContainer.shared.authenticationRefresh = nil
} }
@ -137,13 +134,10 @@ class AuthService: IAuthService {
URLSession.shared.dataTask(with: request) { data, response, error in URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data, if let data = data,
let httpResponse = response as? HTTPURLResponse { let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 { if httpResponse.statusCode == 200, let user = try? JSONDecoder().decode(User.self, from: data) {
if let userJson = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let user = User.mapUser(from: userJson) {
completion(httpResponse.statusCode)
AppStateContainer.shared.user = user AppStateContainer.shared.user = user
WidgetCenter.shared.reloadAllTimelines() WidgetCenter.shared.reloadAllTimelines()
} completion(httpResponse.statusCode)
} else { } else {
completion(httpResponse.statusCode) completion(httpResponse.statusCode)
} }

@ -38,7 +38,7 @@ class CreationBetViewModel: ObservableObject {
resetAllFieldErrors() resetAllFieldErrors()
if let user = AppStateContainer.shared.user { if let user = AppStateContainer.shared.user {
manager.addBet(bet: toBet(theme: theme, description: description, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, status: .inProgress, creator: user, type: selectedOption)) { statusCode in manager.addBet(bet: toBet(theme: theme, description: description, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, status: .inProgress, creator: user.username, type: selectedOption)) { statusCode in
switch statusCode { switch statusCode {
case 201: case 201:
self.betAdded = true self.betAdded = true
@ -113,7 +113,7 @@ class CreationBetViewModel: ObservableObject {
self.errorMessage = errorMessage self.errorMessage = errorMessage
} }
func toBet(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, status: BetStatus, creator: User, type: Int) -> Bet { func toBet(theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, status: BetStatus, creator: String, type: Int) -> Bet {
switch type { switch type {
case 0: case 0:
return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: []) return BinaryBet(theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [])

@ -54,6 +54,7 @@ struct BetEndingValidationView: View {
Text("Ce bet est arrivé à la date de fin. Vous devez à présent distribuer les gains en validant le pari gagnant.") Text("Ce bet est arrivé à la date de fin. Vous devez à présent distribuer les gains en validant le pari gagnant.")
.textStyle(weight: .regular, color: AllInColors.grey800Color, size: 13) .textStyle(weight: .regular, color: AllInColors.grey800Color, size: 13)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
Text("Veuillez choisir la réponse finale:") Text("Veuillez choisir la réponse finale:")
.font(.system(size: 17)) .font(.system(size: 17))
.foregroundStyle(.white) .foregroundStyle(.white)
@ -61,8 +62,9 @@ struct BetEndingValidationView: View {
.padding(.top, 30) .padding(.top, 30)
.padding(.bottom, 10) .padding(.bottom, 10)
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
VStack(spacing: 14){ VStack(spacing: 14){
ForEach(bet.answers, id: \.self) { answer in ForEach(bet.answers) { answer in
ChoiceFinalAnswerCell(selected : answer.response == viewModel.selectedAnswer, answer: answer).onTapGesture { ChoiceFinalAnswerCell(selected : answer.response == viewModel.selectedAnswer, answer: answer).onTapGesture {
if(viewModel.selectedAnswer == answer.response){ if(viewModel.selectedAnswer == answer.response){
viewModel.selectedAnswer = nil viewModel.selectedAnswer = nil

@ -66,7 +66,7 @@ struct DetailsView: View {
Text("proposé par") Text("proposé par")
.font(.system(size: 10)) .font(.system(size: 10))
.foregroundColor(AllInColors.grey800Color) .foregroundColor(AllInColors.grey800Color)
Text((viewModel.betDetail?.bet.author.username ?? "Unknown").capitalized) Text((viewModel.betDetail?.bet.author ?? "Unknown").capitalized)
.font(.system(size: 10)) .font(.system(size: 10))
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(AllInColors.primaryTextColor) .foregroundColor(AllInColors.primaryTextColor)
@ -122,8 +122,8 @@ struct DetailsView: View {
.fontWeight(.bold) .fontWeight(.bold)
.padding(.bottom, 10) .padding(.bottom, 10)
ScrollView(showsIndicators: false) { ScrollView(showsIndicators: false) {
ForEach(viewModel.betDetail?.participations ?? []) { (participation: Participation) in ForEach(viewModel.betDetail?.participations ?? []) { participation in
ParticiationCell(participation: participation).padding(.horizontal, 10) ParticipationCell(participation: participation).padding(.horizontal, 10)
} }
} }
.padding(.bottom, geometry.safeAreaInsets.bottom + 28) .padding(.bottom, geometry.safeAreaInsets.bottom + 28)

@ -18,7 +18,7 @@
1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF612B4EC67000374ABF /* ReviewCard.swift */; }; 1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF612B4EC67000374ABF /* ReviewCard.swift */; };
129D051D2B6E7FF0003D3E08 /* OddCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */; }; 129D051D2B6E7FF0003D3E08 /* OddCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */; };
12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */; }; 12C370482B5A5EE500CD9F0F /* BetLineLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */; };
12C3704A2B5D5BD000CD9F0F /* ParticiationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370492B5D5BD000CD9F0F /* ParticiationCell.swift */; }; 12C3704A2B5D5BD000CD9F0F /* ParticipationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C370492B5D5BD000CD9F0F /* ParticipationCell.swift */; };
EC0193782B25BF16005D81E6 /* AllcoinsCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */; }; EC0193782B25BF16005D81E6 /* AllcoinsCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */; };
EC01937A2B25C12B005D81E6 /* BetCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193792B25C12B005D81E6 /* BetCard.swift */; }; EC01937A2B25C12B005D81E6 /* BetCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0193792B25C12B005D81E6 /* BetCard.swift */; };
EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */; }; EC01937C2B25C2A8005D81E6 /* AllcoinsCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */; };
@ -154,7 +154,7 @@
1244EF612B4EC67000374ABF /* ReviewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewCard.swift; sourceTree = "<group>"; }; 1244EF612B4EC67000374ABF /* ReviewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewCard.swift; sourceTree = "<group>"; };
129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OddCapsule.swift; sourceTree = "<group>"; }; 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OddCapsule.swift; sourceTree = "<group>"; };
12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetLineLoading.swift; sourceTree = "<group>"; }; 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetLineLoading.swift; sourceTree = "<group>"; };
12C370492B5D5BD000CD9F0F /* ParticiationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticiationCell.swift; sourceTree = "<group>"; }; 12C370492B5D5BD000CD9F0F /* ParticipationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipationCell.swift; sourceTree = "<group>"; };
EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCapsule.swift; sourceTree = "<group>"; }; EC0193772B25BF16005D81E6 /* AllcoinsCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCapsule.swift; sourceTree = "<group>"; };
EC0193792B25C12B005D81E6 /* BetCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetCard.swift; sourceTree = "<group>"; }; EC0193792B25C12B005D81E6 /* BetCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetCard.swift; sourceTree = "<group>"; };
EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCounter.swift; sourceTree = "<group>"; }; EC01937B2B25C2A8005D81E6 /* AllcoinsCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllcoinsCounter.swift; sourceTree = "<group>"; };
@ -420,7 +420,7 @@
120919172B56D0AE00D0FA29 /* ParticipationModal.swift */, 120919172B56D0AE00D0FA29 /* ParticipationModal.swift */,
120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */, 120919192B56DC6C00D0FA29 /* DropDownAnswerMenu.swift */,
12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */, 12C370472B5A5EE500CD9F0F /* BetLineLoading.swift */,
12C370492B5D5BD000CD9F0F /* ParticiationCell.swift */, 12C370492B5D5BD000CD9F0F /* ParticipationCell.swift */,
123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */, 123225DA2B67E41400D30BB3 /* ChoiceFinalAnswerCell.swift */,
129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */, 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */,
); );
@ -693,7 +693,7 @@
EC3077072B24CB840060E34D /* SplashView.swift in Sources */, EC3077072B24CB840060E34D /* SplashView.swift in Sources */,
EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */, EC01937E2B25C52E005D81E6 /* TopBar.swift in Sources */,
ECA9D1CB2B2DA2320076E0EC /* DropDownFriends.swift in Sources */, ECA9D1CB2B2DA2320076E0EC /* DropDownFriends.swift in Sources */,
12C3704A2B5D5BD000CD9F0F /* ParticiationCell.swift in Sources */, 12C3704A2B5D5BD000CD9F0F /* ParticipationCell.swift in Sources */,
123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */, 123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */,
EC01FCC32B56650400BB2390 /* DetailsViewModel.swift in Sources */, EC01FCC32B56650400BB2390 /* DetailsViewModel.swift in Sources */,
ECB26A1B2B40746C00FE06B3 /* FriendsViewModel.swift in Sources */, ECB26A1B2B40746C00FE06B3 /* FriendsViewModel.swift in Sources */,

@ -31,62 +31,25 @@ public class FactoryApiBet: FactoryBet {
return json return json
} }
public func fromJsonDateString(_ dateString: String) -> Date? {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let date = formatter.date(from: dateString)
return date
}
public func toBet(from json: [String: Any]) -> Bet? { public func toBet(from json: [String: Any]) -> Bet? {
guard let id = json["id"] as? String, guard let type = json["type"] as? String, let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) else {
let theme = json["theme"] as? String,
let phrase = json["sentenceBet"] as? String,
let endRegisterDateString = json["endRegistration"] as? String,
let endBetDateString = json["endBet"] as? String,
let isPublic = json["isPrivate"] as? Bool,
let createdBy = json["createdBy"] as? String,
let type = json["type"] as? String,
let status = json["status"] as? String else {
return nil
}
guard let endRegisterDate = fromJsonDateString(endRegisterDateString),
let endBetDate = fromJsonDateString(endBetDateString) else {
return nil return nil
} }
let decoder = JSONDecoder()
return toBet(id: id, theme: theme, description: phrase, endRegister: endRegisterDate, endBet: endBetDate, isPublic: isPublic, status: toStatus(status: status), creator: User(username: createdBy, email: createdBy, nbCoins: 0, friends: []), type: type) do {
}
func toStatus(status: String) -> BetStatus {
switch status {
case "IN_PROGRESS":
return .inProgress
case "WAITING":
return .waiting
case "CLOSING":
return .closing
case "FINISHED":
return .finished
case "CANCELLED":
return .cancelled
default:
return .finished
}
}
public func toBet(id: String, theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, status: BetStatus, creator: User, type: String) -> Bet {
switch type { switch type {
case "BINARY": case "BINARY":
return BinaryBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: []) return try decoder.decode(BinaryBet.self, from: jsonData)
case "MATCH": case "MATCH":
return MatchBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: [], nameTeam1: "", nameTeam2: "") return try decoder.decode(MatchBet.self, from: jsonData)
case "CUSTOM": case "CUSTOM":
return CustomBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: []) return try decoder.decode(CustomBet.self, from: jsonData)
default: default:
return BinaryBet(id: id, theme: theme, phrase: description, endRegisterDate: endRegister, endBetDate: endBet, isPublic: isPublic, status: status, invited: [], author: creator, registered: []) return try decoder.decode(BinaryBet.self, from: jsonData)
}
} catch {
print("Error decoding Bet object: \(error)")
return nil
} }
} }
@ -98,51 +61,27 @@ public class FactoryApiBet: FactoryBet {
var participations: [Participation] = [] var participations: [Participation] = []
if let participationsJson = json["participations"] as? [[String: Any]], !participationsJson.isEmpty { if let participationsJson = json["participations"] as? [[String: Any]] {
for participationJson in participationsJson { do {
if let participation = self.toParticipate(from: participationJson) { participations = try JSONDecoder().decode([Participation].self, from: JSONSerialization.data(withJSONObject: participationsJson))
participations.append(participation) } catch {
} print("Error decoding participations: \(error)")
} }
} }
var answers: [AnswerDetail] = [] var answers: [AnswerDetail] = []
if let answersJson = json["answers"] as? [[String: Any]], !answersJson.isEmpty { if let answersJson = json["answers"] as? [[String: Any]] {
for answer in answersJson { do {
if let answer = self.toAnswer(from: answer) { answers = try JSONDecoder().decode([AnswerDetail].self, from: JSONSerialization.data(withJSONObject: answersJson))
answers.append(answer) } catch {
} print("Error decoding answers: \(error)")
} }
} }
return BetDetail(bet: bet, answers: answers, participations: participations) return BetDetail(bet: bet, answers: answers, participations: participations)
} }
public func toParticipate(from json: [String: Any]) -> Participation? {
guard let id = json["id"] as? String,
let betId = json["betId"] as? String,
let username = json["username"] as? String,
let answer = json["answer"] as? String,
let stake = json["stake"] as? Int else {
return nil
}
return Participation(id: id, stake: stake, date: Date(), response: answer, user: User(username: username, email: "Email", nbCoins: 0, friends: []), betId: betId)
}
public func toAnswer(from json: [String: Any]) -> AnswerDetail? {
guard let response = json["response"] as? String,
let totalStakes = json["totalStakes"] as? Int,
let totalParticipants = json["totalParticipants"] as? Int,
let highestStake = json["highestStake"] as? Int,
let odds = json["odds"] as? Float else {
return nil
}
return AnswerDetail(response: response, totalStakes: totalStakes, totalParticipants: totalParticipants, highestStake: highestStake, odds: odds)
}
public func betTypeString(fromType type: String) -> String { public func betTypeString(fromType type: String) -> String {
switch type { switch type {
case "BinaryBet": case "BinaryBet":

@ -8,7 +8,7 @@
import Foundation import Foundation
/// A class representing detailed information about a specific answer option for a bet. /// A class representing detailed information about a specific answer option for a bet.
public class AnswerDetail: ObservableObject, Hashable { public class AnswerDetail: ObservableObject, Identifiable, Codable {
/// The response or outcome associated with this answer. /// The response or outcome associated with this answer.
public private(set) var response: String public private(set) var response: String
@ -41,16 +41,4 @@ public class AnswerDetail: ObservableObject, Hashable {
self.odds = odds self.odds = odds
} }
public func hash(into hasher: inout Hasher) {
// Use properties that define the uniqueness of the instance for hashing
hasher.combine(response)
// ... (combine other properties)
}
public static func == (lhs: AnswerDetail, rhs: AnswerDetail) -> Bool {
// Check equality based on properties
return lhs.response == rhs.response
// ... (check other properties)
}
} }

@ -8,7 +8,7 @@
import Foundation import Foundation
/// A class representing a betting entity, including details about the bet theme, participants, and deadlines. /// A class representing a betting entity, including details about the bet theme, participants, and deadlines.
public class Bet: ObservableObject, Identifiable { public class Bet: ObservableObject, Identifiable, Codable {
/// The id for the bet. /// The id for the bet.
public private(set) var id: String public private(set) var id: String
@ -32,14 +32,41 @@ public class Bet: ObservableObject, Identifiable {
public private(set) var status: BetStatus public private(set) var status: BetStatus
/// List of users who are invited to participate in the bet. /// List of users who are invited to participate in the bet.
public private(set) var invited: [User] public private(set) var invited: [User] = []
/// The user who created the bet. /// The user who created the bet.
public private(set) var author: User public private(set) var author: String
/// List of users who have registered for the bet. /// List of users who have registered for the bet.
public private(set) var registered: [User] public private(set) var registered: [User] = []
private enum CodingKeys: String, CodingKey {
case id
case theme
case phrase = "sentenceBet"
case endRegisterDate = "endRegistration"
case endBetDate = "endBet"
case isPublic = "isPrivate"
case status
case author = "createdBy"
}
public required init(from decoder: Decoder) throws {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(String.self, forKey: .id)
self.theme = try container.decode(String.self, forKey: .theme)
self.phrase = try container.decode(String.self, forKey: .phrase)
let endRegisterDateString = try container.decode(String.self, forKey: .endRegisterDate)
self.endRegisterDate = formatter.date(from: endRegisterDateString)!
let endBetDateString = try container.decode(String.self, forKey: .endBetDate)
self.endBetDate = formatter.date(from: endBetDateString)!
self.isPublic = try container.decode(Bool.self, forKey: .isPublic)
self.status = try container.decode(BetStatus.self, forKey: .status)
self.author = try container.decode(String.self, forKey: .author)
}
/// Custom Constructor /// Custom Constructor
/// ///
@ -54,7 +81,7 @@ public class Bet: ObservableObject, Identifiable {
/// - invited: List of users who are invited to participate in the bet. /// - invited: List of users who are invited to participate in the bet.
/// - author: The user who created the bet. /// - author: The user who created the bet.
/// - registered: List of users who have registered for the bet. /// - registered: List of users who have registered for the bet.
public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: User, registered: [User]) { public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: String, registered: [User]) {
self.id = id self.id = id
self.theme = theme self.theme = theme
self.phrase = phrase self.phrase = phrase
@ -79,7 +106,7 @@ public class Bet: ObservableObject, Identifiable {
/// - invited: List of users who are invited to participate in the bet. /// - invited: List of users who are invited to participate in the bet.
/// - author: The user who created the bet. /// - author: The user who created the bet.
/// - registered: List of users who have registered for the bet. /// - registered: List of users who have registered for the bet.
public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: User, registered: [User]) { public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: String, registered: [User]) {
self.id = UUID().uuidString self.id = UUID().uuidString
self.theme = theme self.theme = theme
self.phrase = phrase self.phrase = phrase
@ -92,14 +119,4 @@ public class Bet: ObservableObject, Identifiable {
self.registered = registered self.registered = registered
} }
/// Adds a new user to the list of registered participants for the bet.
///
/// - Parameter newUser: The user to be added to the list of registered participants.
public func addRegistered(newUser: User){
self.registered.append(newUser)
}
public func isFinish() -> Bool{
self.endBetDate < Date()
}
} }

@ -47,12 +47,6 @@ public class BetDetail: ObservableObject {
/// ///
/// - Parameter newParticipation: The new user participation to be added. /// - Parameter newParticipation: The new user participation to be added.
public func addParticipation(newParticipation: Participation) { public func addParticipation(newParticipation: Participation) {
if !self.bet.registered.contains(where: { existingUser in
return existingUser.email == newParticipation.user.email
}) {
self.bet.addRegistered(newUser: newParticipation.user)
}
self.participations.append(newParticipation) self.participations.append(newParticipation)
} }
} }

@ -7,6 +7,11 @@
import Foundation import Foundation
public enum BetStatus { public enum BetStatus: String, Codable {
case inProgress, waiting, closing, finished, cancelled case inProgress = "IN_PROGRESS"
case waiting = "WAITING"
case closing = "CLOSING"
case finished = "FINISHED"
case cancelled = "CANCELLED"
} }

@ -11,5 +11,4 @@ public protocol FactoryBet {
func toResponse(bet: Bet) -> [String: Any] func toResponse(bet: Bet) -> [String: Any]
func toBet(from json: [String: Any]) -> Bet? func toBet(from json: [String: Any]) -> Bet?
func toBetDetail(from json: [String: Any]) -> BetDetail? func toBetDetail(from json: [String: Any]) -> BetDetail?
func toBet(id: String, theme: String, description: String, endRegister: Date, endBet: Date, isPublic: Bool, status: BetStatus, creator: User, type: String) -> Bet
} }

@ -15,6 +15,11 @@ public class MatchBet: Bet {
/// The name of the second team involved in the match. /// The name of the second team involved in the match.
public var nameTeam2: String public var nameTeam2: String
private enum CodingKeys: String, CodingKey {
case nameTeam1
case nameTeam2
}
/// Custom Constructor /// Custom Constructor
/// ///
/// - Parameters: /// - Parameters:
@ -30,7 +35,7 @@ public class MatchBet: Bet {
/// - registered: List of users who have registered for the match bet. /// - registered: List of users who have registered for the match bet.
/// - nameTeam1: The name of the first team involved in the match. /// - nameTeam1: The name of the first team involved in the match.
/// - nameTeam2: The name of the second team involved in the match. /// - nameTeam2: The name of the second team involved in the match.
public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: User, registered: [User], nameTeam1: String, nameTeam2: String) { public init(id: String, theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: String, registered: [User], nameTeam1: String, nameTeam2: String) {
self.nameTeam1 = nameTeam1 self.nameTeam1 = nameTeam1
self.nameTeam2 = nameTeam2 self.nameTeam2 = nameTeam2
super.init(id: id, theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, isPublic: isPublic, status: status, invited: invited, author: author, registered: registered) super.init(id: id, theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, isPublic: isPublic, status: status, invited: invited, author: author, registered: registered)
@ -50,9 +55,24 @@ public class MatchBet: Bet {
/// - registered: List of users who have registered for the match bet. /// - registered: List of users who have registered for the match bet.
/// - nameTeam1: The name of the first team involved in the match. /// - nameTeam1: The name of the first team involved in the match.
/// - nameTeam2: The name of the second team involved in the match. /// - nameTeam2: The name of the second team involved in the match.
public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: User, registered: [User], nameTeam1: String, nameTeam2: String) { public init(theme: String, phrase: String, endRegisterDate: Date, endBetDate: Date, isPublic: Bool, status: BetStatus, invited: [User], author: String, registered: [User], nameTeam1: String, nameTeam2: String) {
self.nameTeam1 = nameTeam1 self.nameTeam1 = nameTeam1
self.nameTeam2 = nameTeam2 self.nameTeam2 = nameTeam2
super.init(theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, isPublic: isPublic, status: status, invited: invited, author: author, registered: registered) super.init(theme: theme, phrase: phrase, endRegisterDate: endRegisterDate, endBetDate: endBetDate, isPublic: isPublic, status: status, invited: invited, author: author, registered: registered)
} }
public required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.nameTeam1 = try container.decode(String.self, forKey: .nameTeam1)
self.nameTeam2 = try container.decode(String.self, forKey: .nameTeam2)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(nameTeam1, forKey: .nameTeam1)
try container.encode(nameTeam2, forKey: .nameTeam2)
try super.encode(to: encoder)
}
} }

@ -8,20 +8,18 @@
import Foundation import Foundation
/// A class representing a user's participation in a bet. /// A class representing a user's participation in a bet.
public class Participation: ObservableObject, Identifiable { public class Participation: ObservableObject, Codable, Identifiable {
public let id: String public let id: String
/// The amount of stake in the bet. /// The amount of stake in the bet.
public private(set) var stake: Int public private(set) var stake: Int
/// The date and time when the participation occurred.
public private(set) var date: Date
/// The response or outcome of the participation. /// The response or outcome of the participation.
public private(set) var response: String public private(set) var answer: String
/// The user who participated in the bet. /// The user who participated in the bet.
public private(set) var user: User public private(set) var username: String
/// The unique identifier of the bet. /// The unique identifier of the bet.
public private(set) var betId: String public private(set) var betId: String
@ -34,12 +32,11 @@ public class Participation: ObservableObject, Identifiable {
/// - response: The response or outcome of the participation. /// - response: The response or outcome of the participation.
/// - user: The user who participated in the bet. /// - user: The user who participated in the bet.
/// - betId: The unique identifier of the bet. /// - betId: The unique identifier of the bet.
public init(id: String, stake: Int, date: Date, response: String, user: User, betId: String) { public init(id: String, stake: Int, answer: String, username: String, betId: String) {
self.id = id self.id = id
self.stake = stake self.stake = stake
self.date = date self.answer = answer
self.response = response self.username = username
self.user = user
self.betId = betId self.betId = betId
} }
} }

@ -8,7 +8,7 @@
import Foundation import Foundation
/// A struct representing a user with details such as username, email, number of coins, and friends. /// A struct representing a user with details such as username, email, number of coins, and friends.
public struct User { public struct User: Codable {
/// The username of the user. /// The username of the user.
public private(set) var username: String public private(set) var username: String
@ -19,41 +19,15 @@ public struct User {
/// The number of coins associated with the user. /// The number of coins associated with the user.
public var nbCoins: Int public var nbCoins: Int
/// List of friends associated with the user.
public private(set) var friends: [User]
/// Custom constructor to initialize a User instance. /// Custom constructor to initialize a User instance.
/// ///
/// - Parameters: /// - Parameters:
/// - username: The username of the user. /// - username: The username of the user.
/// - email: The email address of the user. /// - email: The email address of the user.
/// - nbCoins: The number of coins associated with the user. /// - nbCoins: The number of coins associated with the user.
/// - friends: List of friends associated with the user. public init(username: String, email: String, nbCoins: Int) {
public init(username: String, email: String, nbCoins: Int, friends: [User]) {
self.username = username self.username = username
self.email = email self.email = email
self.nbCoins = nbCoins self.nbCoins = nbCoins
self.friends = friends
}
/// Adds a new friend to the list of friends for the user.
///
/// - Parameter user: The user to be added as a friend.
public mutating func addFriend(user: User) {
self.friends.append(user)
}
/// Maps user data from a JSON dictionary to create a User instance.
///
/// - Parameter json: The JSON dictionary containing user data.
/// - Returns: An optional User instance if mapping is successful, otherwise nil.
public static func mapUser(from json: [String: Any]) -> User? {
guard let username = json["username"] as? String,
let email = json["email"] as? String,
let nbCoins = json["nbCoins"] as? Int else {
return nil
}
return User(username: username, email: email, nbCoins: nbCoins, friends: [])
} }
} }

@ -21,16 +21,14 @@ struct Stub {
public mutating func loadBets() { public mutating func loadBets() {
var user1 = User(username: "Lucas", email: "lucas.delanier@etu.uca.fr", nbCoins: 100, friends: []) let user1 = User(username: "Lucas", email: "lucas.delanier@etu.uca.fr", nbCoins: 100)
users.append(user1) users.append(user1)
var user2 = User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75, friends: [user1]) let user2 = User(username: "Imri", email: "emre.kartal@etu.uca.fr", nbCoins: 75)
users.append(user2) users.append(user2)
user1.addFriend(user: user2)
let user3 = User(username: "Arthur", email: "arthur.valin@etu.uca.fr", nbCoins: 30, friends: [user2]) let user3 = User(username: "Arthur", email: "arthur.valin@etu.uca.fr", nbCoins: 30)
users.append(user3) users.append(user3)
user2.addFriend(user: user3)
let bet1 = BinaryBet( let bet1 = BinaryBet(
theme: "Football - Finale de la Ligue des Champions", theme: "Football - Finale de la Ligue des Champions",
@ -40,7 +38,7 @@ struct Stub {
isPublic: true, isPublic: true,
status: .inProgress, status: .inProgress,
invited: [], invited: [],
author: user1, author: "Lucas",
registered: [user2] registered: [user2]
) )
self.bets.append(bet1) self.bets.append(bet1)
@ -53,7 +51,7 @@ struct Stub {
isPublic: false, isPublic: false,
status: .inProgress, status: .inProgress,
invited: [user3], invited: [user3],
author: user1, author: "Lucas",
registered: [user2] registered: [user2]
) )
self.bets.append(bet2) self.bets.append(bet2)
@ -66,7 +64,7 @@ struct Stub {
isPublic: true, isPublic: true,
status: .finished, status: .finished,
invited: [], invited: [],
author: user1, author: "Lucas",
registered: [user2, user1, user3] registered: [user2, user1, user3]
) )
self.bets.append(bet3) self.bets.append(bet3)
@ -79,7 +77,7 @@ struct Stub {
isPublic: false, isPublic: false,
status: .finished, status: .finished,
invited: [user1], invited: [user1],
author: user2, author: "Lucase",
registered: [user3] registered: [user3]
) )
self.bets.append(bet4) self.bets.append(bet4)
@ -89,10 +87,10 @@ struct Stub {
self.betsDetail.append(betDetail) self.betsDetail.append(betDetail)
} }
self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 120, date: Date(), response: "OUI", user: user1, betId: "1")) self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 120, answer: "OUI", username: user1.username, betId: "1"))
self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 20, date: Date(), response: "NON", user: user2, betId: "2")) self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 20, answer: "NON", username: user2.username, betId: "2"))
self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 320, date: Date(), response: "OUI", user: user3, betId: "3")) self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 320, answer: "OUI", username: user3.username, betId: "3"))
self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 320, date: Date(), response: "OUI", user: user3, betId: "3")) self.betsDetail[0].addParticipation(newParticipation: Participation(id: UUID().uuidString, stake: 320, answer: "OUI", username: user3.username, betId: "3"))
} }

Loading…
Cancel
Save