Update UI result

This commit is contained in:
Aditya Siregar 2025-08-16 01:51:37 +07:00
parent 228f6a78c9
commit 104cd987e9
7 changed files with 109 additions and 16 deletions

View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
APP_NAME="meti-frontend" APP_NAME="meti-backend"
PORT="3000" PORT="4000"
echo "🔄 Pulling latest code..." echo "🔄 Pulling latest code..."
git pull git pull
@ -15,7 +15,9 @@ docker rm $APP_NAME 2>/dev/null
echo "🚀 Running new container..." echo "🚀 Running new container..."
docker run -d --name $APP_NAME \ docker run -d --name $APP_NAME \
-p 4002:$PORT \ -p 4001:$PORT \
-v "$(pwd)/infra":/infra:ro \
-v "$(pwd)/templates":/templates:ro \
$APP_NAME:latest $APP_NAME:latest
echo "✅ Deployment complete." echo "✅ Deployment complete."

View File

@ -94,3 +94,25 @@ type CheckVoteStatusResponse struct {
VotedAt *time.Time `json:"voted_at,omitempty"` VotedAt *time.Time `json:"voted_at,omitempty"`
CandidateID *uuid.UUID `json:"candidate_id,omitempty"` CandidateID *uuid.UUID `json:"candidate_id,omitempty"`
} }
type VoteEventDetailsResponse struct {
VoteEvent VoteEventResponse `json:"vote_event"`
TotalParticipants int64 `json:"total_participants"`
TotalVoted int64 `json:"total_voted"`
TotalNotVoted int64 `json:"total_not_voted"`
}
type UserVoteInfo struct {
UserID uuid.UUID `json:"user_id"`
Username string `json:"username"`
FullName string `json:"full_name"`
VotedAt time.Time `json:"voted_at"`
CandidateID uuid.UUID `json:"candidate_id"`
CandidateName string `json:"candidate_name"`
}
type UserBasicInfo struct {
UserID uuid.UUID `json:"user_id"`
Username string `json:"username"`
FullName string `json:"full_name"`
}

View File

@ -26,6 +26,7 @@ type VoteEventService interface {
SubmitVote(ctx context.Context, userID uuid.UUID, req *contract.SubmitVoteRequest) (*contract.VoteResponse, error) SubmitVote(ctx context.Context, userID uuid.UUID, req *contract.SubmitVoteRequest) (*contract.VoteResponse, error)
GetVoteResults(ctx context.Context, eventID uuid.UUID) (*contract.VoteResultsResponse, error) GetVoteResults(ctx context.Context, eventID uuid.UUID) (*contract.VoteResultsResponse, error)
CheckVoteStatus(ctx context.Context, userID, eventID uuid.UUID) (*contract.CheckVoteStatusResponse, error) CheckVoteStatus(ctx context.Context, userID, eventID uuid.UUID) (*contract.CheckVoteStatusResponse, error)
GetVoteEventDetails(ctx context.Context, eventID uuid.UUID) (*contract.VoteEventDetailsResponse, error)
} }
type VoteEventHandler struct { type VoteEventHandler struct {
@ -305,6 +306,26 @@ func (h *VoteEventHandler) sendErrorResponse(c *gin.Context, message string, sta
c.JSON(statusCode, errorResponse) c.JSON(statusCode, errorResponse)
} }
func (h *VoteEventHandler) GetVoteEventDetails(c *gin.Context) {
eventIDStr := c.Param("id")
eventID, err := uuid.Parse(eventIDStr)
if err != nil {
logger.FromContext(c).WithError(err).Error("VoteEventHandler::GetVoteEventDetails -> Invalid event ID")
h.sendValidationErrorResponse(c, "Invalid event ID", constants.MalformedFieldErrorCode)
return
}
details, err := h.voteEventService.GetVoteEventDetails(c.Request.Context(), eventID)
if err != nil {
logger.FromContext(c).WithError(err).Error("VoteEventHandler::GetVoteEventDetails -> Failed to get vote event details")
h.sendErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
logger.FromContext(c).Infof("VoteEventHandler::GetVoteEventDetails -> Successfully retrieved vote event details")
c.JSON(http.StatusOK, contract.BuildSuccessResponse(details))
}
func (h *VoteEventHandler) sendValidationErrorResponse(c *gin.Context, message string, errorCode string) { func (h *VoteEventHandler) sendValidationErrorResponse(c *gin.Context, message string, errorCode string) {
statusCode := constants.HttpErrorMap[errorCode] statusCode := constants.HttpErrorMap[errorCode]
if statusCode == 0 { if statusCode == 0 {

View File

@ -120,3 +120,21 @@ func (r *VoteEventRepositoryImpl) GetVoteResults(ctx context.Context, eventID uu
return resultMap, nil return resultMap, nil
} }
func (r *VoteEventRepositoryImpl) GetVotedCount(ctx context.Context, eventID uuid.UUID) (int64, error) {
var count int64
err := r.db.WithContext(ctx).
Model(&entities.Vote{}).
Where("vote_event_id = ?", eventID).
Count(&count).Error
return count, err
}
func (r *VoteEventRepositoryImpl) GetTotalActiveUsersCount(ctx context.Context) (int64, error) {
var count int64
err := r.db.WithContext(ctx).
Model(&entities.User{}).
Where("is_active = ?", true).
Count(&count).Error
return count, err
}

View File

@ -93,4 +93,5 @@ type VoteEventHandler interface {
GetVoteResults(c *gin.Context) GetVoteResults(c *gin.Context)
CheckVoteStatus(c *gin.Context) CheckVoteStatus(c *gin.Context)
GetCandidates(c *gin.Context) GetCandidates(c *gin.Context)
GetVoteEventDetails(c *gin.Context)
} }

View File

@ -174,6 +174,7 @@ func (r *Router) addAppRoutes(rg *gin.Engine) {
voteEvents.GET("/:id/candidates", r.voteEventHandler.GetCandidates) voteEvents.GET("/:id/candidates", r.voteEventHandler.GetCandidates)
voteEvents.GET("/:id/results", r.voteEventHandler.GetVoteResults) voteEvents.GET("/:id/results", r.voteEventHandler.GetVoteResults)
voteEvents.GET("/:id/vote-status", r.voteEventHandler.CheckVoteStatus) voteEvents.GET("/:id/vote-status", r.voteEventHandler.CheckVoteStatus)
voteEvents.GET("/:id/details", r.voteEventHandler.GetVoteEventDetails)
} }
candidates := v1.Group("/candidates") candidates := v1.Group("/candidates")

View File

@ -23,6 +23,8 @@ type VoteEventRepository interface {
SubmitVote(ctx context.Context, vote *entities.Vote) error SubmitVote(ctx context.Context, vote *entities.Vote) error
HasUserVoted(ctx context.Context, userID, eventID uuid.UUID) (bool, error) HasUserVoted(ctx context.Context, userID, eventID uuid.UUID) (bool, error)
GetVoteResults(ctx context.Context, eventID uuid.UUID) (map[uuid.UUID]int64, error) GetVoteResults(ctx context.Context, eventID uuid.UUID) (map[uuid.UUID]int64, error)
GetVotedCount(ctx context.Context, eventID uuid.UUID) (int64, error)
GetTotalActiveUsersCount(ctx context.Context) (int64, error)
} }
type VoteEventServiceImpl struct { type VoteEventServiceImpl struct {
@ -256,3 +258,29 @@ func (s *VoteEventServiceImpl) CheckVoteStatus(ctx context.Context, userID, even
return response, nil return response, nil
} }
func (s *VoteEventServiceImpl) GetVoteEventDetails(ctx context.Context, eventID uuid.UUID) (*contract.VoteEventDetailsResponse, error) {
voteEvent, err := s.voteEventRepo.GetByID(ctx, eventID)
if err != nil {
return nil, err
}
totalParticipants, err := s.voteEventRepo.GetTotalActiveUsersCount(ctx)
if err != nil {
return nil, err
}
totalVoted, err := s.voteEventRepo.GetVotedCount(ctx, eventID)
if err != nil {
return nil, err
}
totalNotVoted := totalParticipants - totalVoted
return &contract.VoteEventDetailsResponse{
VoteEvent: *transformer.VoteEventToContract(voteEvent),
TotalParticipants: totalParticipants,
TotalVoted: totalVoted,
TotalNotVoted: totalNotVoted,
}, nil
}