Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions app/src/main/graphql/User.graphql
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
fragment userFields on User {
id
email
name
netId
name
encodedImage
activeStreak
maxStreak
streakStart
workoutGoal
lastGoalChange
lastStreak
totalGymDays
}

fragment workoutFields on Workout {
id
workoutTime
userId
facilityId
gymName
}

mutation CreateUser($email: String!, $name: String!, $netId: String!) {
Expand All @@ -33,7 +43,7 @@ query getUserByNetId($netId: String!) {
}
}

mutation SetWorkoutGoals($id: Int!, $workoutGoal: [String!]!) {
mutation SetWorkoutGoals($id: Int!, $workoutGoal: Int!) {
setWorkoutGoals(userId: $id, workoutGoal: $workoutGoal) {
...userFields
}
Expand Down
93 changes: 60 additions & 33 deletions app/src/main/graphql/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,6 @@ type Query {
"""
getAllReports: [Report]

"""
Get the workout goals of a user by ID.
"""
getWorkoutGoals(id: Int!): [String]

"""
Get the current and max workout streak of a user.
"""
getUserStreak(id: Int!): JSONString

"""
Get all facility hourly average capacities.
"""
Expand Down Expand Up @@ -358,39 +348,39 @@ type User {

name: String!

activeStreak: Int
activeStreak: Int!

maxStreak: Int!

workoutGoal: Int

maxStreak: Int
lastGoalChange: DateTime

workoutGoal: [DayOfWeekGraphQLEnum]
lastStreak: Int!

encodedImage: String

giveaways: [Giveaway]

goalHistory: [WorkoutGoalHistory]

friendRequestsSent: [Friendship]

friendRequestsReceived: [Friendship]

friendships: [Friendship]

friends: [User]
}

enum DayOfWeekGraphQLEnum {
MONDAY

TUESDAY

WEDNESDAY

THURSDAY

FRIDAY

SATURDAY
"""
Get the total number of gym days (unique workout days) for user.
"""
totalGymDays: Int!

SUNDAY
"""
The start date of the most recent active streak, up until the current date.
"""
streakStart: Date
}

type Giveaway {
Expand All @@ -401,6 +391,18 @@ type Giveaway {
users: [User]
}

type WorkoutGoalHistory {
id: ID!

userId: Int!

workoutGoal: Int!

effectiveAt: DateTime!

user: User
}

type Friendship {
id: ID!

Expand All @@ -419,6 +421,13 @@ type Friendship {
friend: User
}

"""
The `Date` scalar type represents a Date
value as specified by
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
"""
scalar Date

type Workout {
id: ID!

Expand All @@ -427,12 +436,9 @@ type Workout {
userId: Int!

facilityId: Int!
}

"""
JSON String
"""
scalar JSONString
gymName: String!
}

type HourlyAverageCapacity {
id: ID!
Expand All @@ -448,6 +454,22 @@ type HourlyAverageCapacity {
history: [Float]!
}

enum DayOfWeekGraphQLEnum {
MONDAY

TUESDAY

WEDNESDAY

THURSDAY

FRIDAY

SATURDAY

SUNDAY
}

type CapacityReminder {
id: ID!

Expand Down Expand Up @@ -518,7 +540,7 @@ type Mutation {
"""
Set a user's workout goals.
"""
setWorkoutGoals("The ID of the user." userId: Int!, "The new workout goal for the user in terms of days of the week." workoutGoal: [String]!): User
setWorkoutGoals("The ID of the user." userId: Int!, "The new workout goal for the user in terms of number of days per week." workoutGoal: Int!): User

"""
Log a user's workout.
Expand All @@ -545,6 +567,11 @@ type Mutation {
"""
createReport(createdAt: DateTime!, description: String!, gymId: Int!, issue: String!): CreateReport

"""
Deletes a report by ID.
"""
deleteReport(reportId: Int!): Report

"""
Deletes a user by ID.
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package com.cornellappdev.uplift.data.models
import kotlinx.serialization.Serializable


@Serializable
data class UserInfo(
val id: String,
val email: String,
val name: String,
val netId: String,
val encodedImage: String?,
val activeStreak: Int?,
val maxStreak: Int?,
val streakStart: String?,
val workoutGoal: Int?,
val totalGymDays: Int
)
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,14 @@ class CheckInRepository @Inject constructor(
* Logs a completed workout to the backend. Returns true if the mutation succeeded, false otherwise.
*/
suspend fun logWorkoutFromCheckIn(gymId: Int): Boolean {
val userId = userInfoRepository.getUserIdFromDataStore()?.toIntOrNull() ?: return false
val userIdString = userInfoRepository.getUserIdFromDataStore()
val userId = userIdString?.toIntOrNull()

if (userId == null) {
Log.e("CheckInRepository", "Missing or invalid userId in DataStore: $userIdString")
return false
}

val time = Instant.now().toString()

return try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package com.cornellappdev.uplift.data.repositories

import android.util.Log
import com.apollographql.apollo.ApolloClient
import com.cornellappdev.uplift.GetUserByNetIdQuery
import com.cornellappdev.uplift.GetWeeklyWorkoutDaysQuery
import com.cornellappdev.uplift.GetWorkoutsByIdQuery
import com.cornellappdev.uplift.SetWorkoutGoalsMutation
import java.time.Instant
import javax.inject.Inject
import javax.inject.Singleton

data class ProfileData(
val name: String,
val netId: String,
val encodedImage: String?,
val totalGymDays: Int,
val activeStreak: Int,
val maxStreak: Int,
val streakStart: String?,
val workoutGoal: Int,
val workouts: List<WorkoutDomain>,
val weeklyWorkoutDays: List<String>
)

data class WorkoutDomain(
val gymName: String,
val timestamp: Long
)

@Singleton
class ProfileRepository @Inject constructor(
private val userInfoRepository: UserInfoRepository,
private val apolloClient: ApolloClient
) {
suspend fun getProfile(): Result<ProfileData> {
return try{
val netId = userInfoRepository.getNetIdFromDataStore()
?: return Result.failure(Exception("NetId missing"))

val userResponse = apolloClient.query(
GetUserByNetIdQuery(netId)
).execute()

if (userResponse.hasErrors()) {
Log.e("ProfileRepo", "User query errors: ${userResponse.errors}")
return Result.failure(IllegalStateException("User query failed"))
}

val user = userResponse.data?.getUserByNetId?.firstOrNull()?.userFields
?: return Result.failure(IllegalStateException("User not found"))

val userId = user.id.toIntOrNull()
?: return Result.failure(IllegalStateException("Invalid user ID: ${user.id}"))

val workoutResponse = apolloClient
.query(GetWorkoutsByIdQuery(userId))
.execute()

if (workoutResponse.hasErrors()) {
Log.e("ProfileRepo", "Workout query errors: ${workoutResponse.errors}")
}

val workouts = if (workoutResponse.hasErrors()) {
emptyList()
} else {
workoutResponse.data?.getWorkoutsById?.filterNotNull() ?: emptyList()
}

val workoutDomain = workouts.map {
WorkoutDomain(
gymName = it.workoutFields.gymName,
timestamp = Instant.parse(it.workoutFields.workoutTime.toString()).toEpochMilli()
)
}

val weeklyResponse = apolloClient.query(GetWeeklyWorkoutDaysQuery(userId)).execute()
if (weeklyResponse.hasErrors()) {
Log.e("ProfileRepo", "Weekly query errors=${weeklyResponse.errors}")
}

val weeklyDays = if (weeklyResponse.hasErrors()) {
emptyList()
} else {
weeklyResponse.data?.getWeeklyWorkoutDays?.filterNotNull() ?: emptyList()
}

Result.success(
ProfileData(
name = user.name,
netId = user.netId,
encodedImage = user.encodedImage,
totalGymDays = user.totalGymDays,
activeStreak = user.activeStreak,
maxStreak = user.maxStreak,
streakStart = user.streakStart?.toString(),
workoutGoal = user.workoutGoal ?: 0,
workouts = workoutDomain,
weeklyWorkoutDays = weeklyDays
)
)
} catch (e: Exception) {
Log.e("ProfileRepo", "Failed to load profile", e)
Result.failure(e)
}
}

suspend fun setWorkoutGoal(userId: Int, goal: Int): Result<Unit> {
return try {
val response = apolloClient
.mutation(
SetWorkoutGoalsMutation(
id = userId,
workoutGoal = goal
)
)
.execute()

if (response.hasErrors()) {
Result.failure(Exception("Goal update failed"))
} else {
Result.success(Unit)
}

} catch (e: Exception) {
Result.failure(e)
}
}
}
Loading