Consolidate repos

This commit is contained in:
João Silva
2023-11-29 16:30:23 +00:00
parent c31937fd10
commit 979fabe1b2
61 changed files with 5106 additions and 11 deletions

11
.gitignore vendored
View File

@@ -1,11 +1,10 @@
# Python
app/__pycache__/
app/*/__pycache__/
app/*.pyc
backend/*/__pycache__/
backend/*.pyc
# Logs
app/logs/
app/*.log
backend/logs/
backend/*.log
# Environment variables
app/config/.env
backend/config/.env

View File

@@ -8,7 +8,7 @@ RUN apt-get update && apt-get install -y pkg-config python3-dev default-libmysql
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY app/ /app
COPY backend/ /app
# Create a virtual environment and install dependencies
RUN python -m venv /venv
@@ -20,7 +20,6 @@ RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 8000
# Define environment variable
#ENV NAME World
ENV DB_HOST=""
ENV DB_PORT=3306
ENV DB_USER=""

16
Dockerfile_frontend Normal file
View File

@@ -0,0 +1,16 @@
# Use an official Nginx image as a base image
FROM nginx:latest
# Set the working directory to /app
WORKDIR /app
# Copy the PHP files into the container
COPY frontend/ /app
# Copy the Nginx configuration file
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose port 80 to the outside world
EXPOSE 80
# Define environment variable

View File

@@ -1,9 +1,21 @@
version: '3'
services:
gearguardian-frontend:
image: gearguardian-frontend:latest
volumes:
- ./app:/app
- ./nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "8080:80"
networks:
- frontend_network
- backend_network
restart: unless-stopped
# API logic
gearguardian-api:
container_name: gearguardian-api
image: your-image-name
gearguardian-backend:
container_name: gearguardian-backend
image: gearguardian-backend:latest
environment:
- DB_HOST=<change me> #required
- DB_PORT=3306 #optional - will use port 3306 by default
@@ -85,4 +97,6 @@ services:
networks:
backend_network:
driver: bridge
frontend_network:
driver: bridge

View File

@@ -0,0 +1,755 @@
<?php
if(!isset($_SESSION)){
session_start();
}
require_once $_SERVER['DOCUMENT_ROOT']."/inc/sqlFunctions.php";
$page="activity";
$activity = [];
$addGearToActivity = -9000;
$editGearActivity = -9000;
$deleteGearActivity = -9000;
$deleteActivity = -9000;
if(!isLogged()){
header("Location: ../login.php");
}
if(!isTokenValid($_SESSION["token"])){
header("Location: ../logout.php?sessionExpired=1");
}
if(!isset($_GET["activityID"])){
header("Location: ../index.php?invalidActivity=1");
}
// Load the language file based on the user's preferred language
switch ($_SESSION["preferred_language"]) {
case 'en':
$translationsActivitiesActivity = include $_SERVER['DOCUMENT_ROOT'].'/lang/activities/en.php';
break;
case 'pt':
$translationsActivitiesActivity = include $_SERVER['DOCUMENT_ROOT'].'/lang/activities/pt.php';
break;
// ...
default:
$translationsActivitiesActivity = include $_SERVER['DOCUMENT_ROOT'].'/lang/activities/en.php';
}
/* Add gear to activity action */
if(isset($_GET["addGearToActivity"]) && $_GET["addGearToActivity"] == 1){
$addGearToActivity = addGearToActivity($_GET["activityID"], $_POST["gearIDAdd"]);
}
/* Edit activity gear */
if(isset($_GET["editGearActivity"]) && $_GET["editGearActivity"] == 1){
$editGearActivity = addGearToActivity($_GET["activityID"], $_POST["gearIDEdit"]);
}
/* Delete activity gear */
if(isset($_GET["deleteGearActivity"]) && $_GET["deleteGearActivity"] == 1){
$deleteGearActivity = unsetActivityGear($_GET["activityID"]);
}
/* Delete activity */
if(isset($_GET["deleteActivity"]) && $_GET["deleteActivity"] == 1){
$deleteActivity = deleteActivity($_GET["activityID"]);
if($deleteActivity == 0){
header("Location: ../index.php?deleteActivity=1");
}
}
$activity = getActivityFromId($_GET["activityID"]);
if ($activity == NULL){
header("Location: ../index.php?invalidActivity=1");
}
// HR data for activity
$hrData = [];
$cadData = [];
$powerData = [];
$eleData = [];
$velData = [];
$paceData = [];
foreach ($activity[0]['waypoints'] as $waypoint) {
$hrData[] = $waypoint['hr'];
$cadData[] = $waypoint['cad'];
$powerData[] = $waypoint['power'];
$eleData[] = $waypoint['ele'];
$velData[] = (float)number_format(($waypoint['vel']*3.6),0);
if($activity[0]["activity_type"] == 1 || $activity[0]["activity_type"] == 2 || $activity[0]["activity_type"] == 3){
if($waypoint['pace'] == 0 || $waypoint['pace'] == null){
$paceData[] = 0;
}else{
$paceData[] = ($waypoint["pace"] * 1000) / 60;
}
}else{
if($activity[0]["activity_type"] == 9){
if($waypoint['pace'] == 0 || $waypoint['pace'] == null){
$paceData[] = 0;
}else{
$paceData[] = ($waypoint["pace"] * 100) / 60;
}
}
}
}
$activityUser = getUserFromId($activity[0]['user_id']);
if($activity[0]["gear_id"] != null){
$activityGear = getGearFromId($activity[0]["gear_id"]);
}
if($activity[0]["activity_type"] == 1 || $activity[0]["activity_type"] == 2 || $activity[0]["activity_type"] == 3){
$activityGearOptions = getGearForRunning();
}else{
if($activity[0]["activity_type"] == 4 || $activity[0]["activity_type"] == 5 || $activity[0]["activity_type"] == 6 || $activity[0]["activity_type"] == 7 || $activity[0]["activity_type"] == 8){
$activityGearOptions = getGearForCycling();
}else{
if($activity[0]["activity_type"] == 9){
$activityGearOptions = getGearForSwimming();
}
}
}
?>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Top.php" ?>
<div class="container mt-4">
<!-- Error banners -->
<?php if($addGearToActivity == -1 || $addGearToActivity == -2 || $editGearActivity == -1 || $editGearActivity == -2 || $deleteGearActivity == -1 || $deleteGearActivity == -2 || $deleteActivity == -1 || $deleteActivity == -2){ ?>
<div class="alert alert-danger alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-exclamation me-1"></i>
<div>
<?php if($addGearToActivity == -1 || $editGearActivity == -1 || $deleteActivity == -1){ ?>
API ERROR | <?php echo $translationsActivitiesActivity['activity_addEditGear_API_error_-1']; ?> (-1).
<?php }else{ ?>
<?php if($addGearToActivity == -2 || $editGearActivity == -2 || $deleteActivity == -2){ ?>
API ERROR | <?php echo $translationsActivitiesActivity['activity_addEditGear_API_error_-2']; ?> (-2).
<?php } ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<!-- Info banners -->
<!-- Success banners -->
<?php if($addGearToActivity == 0 || $editGearActivity == 0 || $deleteGearActivity == 0){ ?>
<div class="alert alert-success alert-dismissible d-flex align-items-center" role="alert">
<div>
<i class="fa-regular fa-circle-check me-1"></i>
<?php if($addGearToActivity == 0){ ?>
<?php echo $translationsActivitiesActivity['activity_success_gearAdded']; ?>
<?php }else{ ?>
<?php if($editGearActivity == 0){ ?>
<?php echo $translationsActivitiesActivity['activity_success_gearEdited']; ?>
<?php }else{ ?>
<?php if($deleteGearActivity == 0){ ?>
<?php echo $translationsActivitiesActivity['activity_success_gearDeleted']; ?>
<?php } ?>
<?php } ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<div class="d-flex justify-content-between">
<!-- Activity user details -->
<div class="d-flex align-items-center">
<img src=<?php if(is_null($activityUser[0]["photo_path"])){ if($activityUser[0]["gender"] == 1){ echo ("../img/avatar/male1.png"); }else{ echo ("../img/avatar/female1.png"); } }else{ echo ($activityUser[0]["photo_path"]); }?> alt="userPicture" class="rounded-circle" width="55" height="55">
<div class="ms-3 me-3">
<div class="fw-bold">
<a href="../users/user.php?userID=<?php echo ($activityUser[0]["id"]); ?>"><?php echo ($activityUser[0]["name"]); ?></a>
</div>
<!-- Activity time and place details -->
<h7><?php if($activity[0]["activity_type"] == 1){ echo '<i class="fa-solid fa-person-running"></i>'; }else{ if($activity[0]["activity_type"] == 4 || $activity[0]["activity_type"] == 5 || $activity[0]["activity_type"] == 6 || $activity[0]["activity_type"] == 7 || $activity[0]["activity_type"] == 8){ echo '<i class="fa-solid fa-person-biking"></i>'; }else{ if($activity[0]["activity_type"] == 9){ echo '<i class="fa-solid fa-person-swimming"></i>'; } } } ?> <?php echo (new DateTime($activity[0]["start_time"]))->format("d/m/y"); ?>@<?php echo (new DateTime($activity[0]["start_time"]))->format("H:i"); ?><?php if(isset($activity[0]["city"]) || isset($activity[0]["country"])){ echo " - "; }?><?php if(isset($activity[0]["city"]) && !empty($activity[0]["city"])){ echo $activity[0]["city"].", " ; }?><?php if(isset($activity[0]["country"]) && !empty($activity[0]["country"])){ echo $activity[0]["country"]; } ?></h7>
</div>
</div>
<div class="dropdown d-flex">
<button class="btn btn-link btn-lg" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="fa-solid fa-ellipsis-vertical"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="https://www.strava.com/activities/<?php echo $activity[0]['strava_activity_id']; ?>"><?php echo $translationsActivitiesActivity['activity_title_dropdown_seeItOnStrava']; ?></a></li>
<li><a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#deleteActivityModal"><?php echo $translationsActivitiesActivity['activity_title_dropdown_deleteActivity']; ?></a></li>
</ul>
</div>
</div>
<!-- Modal delete gear -->
<div class="modal fade" id="deleteActivityModal" tabindex="-1" aria-labelledby="deleteActivityModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="deleteActivityModal"><?php echo $translationsActivitiesActivity['activity_title_dropdown_deleteActivity']; ?></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<?php echo $translationsActivitiesActivity['activity_title_dropdown_deleteActivity_modal_body']; ?> <b><?php echo $activity[0]['name']; ?></b>?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo $translationsTemplateTop['template_top_global_close']; ?></button>
<a type="button" class="btn btn-danger" href="../activities/activity.php?activityID=<?php echo $activity[0]["id"]; ?>&deleteActivity=1"><?php echo $translationsActivitiesActivity['activity_title_dropdown_deleteActivity']; ?></a>
</div>
</div>
</div>
</div>
<!-- Activity title -->
<h1 class="mt-3"><?php echo $activity[0]["name"]; ?></h1>
<!-- Details -->
<div class=" row d-flex mt-3">
<div class="col">
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_detail_distance']; ?></span>
<br>
<?php if($activity[0]["activity_type"] != 9){ ?>
<?php echo number_format(($activity[0]["distance"] / 1000),2); ?> km
<?php }else{ ?>
<?php echo ($activity[0]["distance"]); ?> m
<?php } ?>
</div>
<div class="col border-start border-opacity-50">
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_detail_time']; ?></span>
<br>
<?php
$startDateTime = DateTime::createFromFormat("Y-m-d\TH:i:s", $activity[0]["start_time"]);
$endDateTime = DateTime::createFromFormat("Y-m-d\TH:i:s", $activity[0]["end_time"]);
$interval = $startDateTime->diff($endDateTime);
if ($interval->h < 1) {
// If the difference is less than one hour
echo $interval->i . "m " . $interval->s . "s";
} else {
// If the difference is one hour or more
echo $interval->h . "h " . $interval->i . "m";
}
?>
</div>
<div class="col border-start border-opacity-50">
<?php if($activity[0]["activity_type"] != 9 && $activity[0]["activity_type"] != 1){ ?>
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_detail_elevationGain']; ?></span>
<br>
<?php echo ($activity[0]["elevation_gain"]); ?> m
<?php }else{ ?>
<?php if($activity[0]["activity_type"] == 1 || $activity[0]["activity_type"] == 2 || $activity[0]["activity_type"] == 3){ ?>
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_detail_pace']; ?></span>
<br>
<?php echo floor(($activity[0]["pace"]*1000)/60).":".number_format((((($activity[0]["pace"]*1000)/60) - floor(($activity[0]["pace"]*1000)/60)) * 60),0); ?> min/km
<?php }else{ ?>
<?php if($activity[0]["activity_type"] == 9){ ?>
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_detail_pace']; ?></span>
<br>
<?php echo floor(($activity[0]["pace"]*100)/60).":".number_format((((($activity[0]["pace"]*100)/60) - floor(($activity[0]["pace"]*100)/60)) * 60),0); ?> min/100m
<?php } ?>
<?php } ?>
<?php } ?>
</div>
</div>
<!-- other metrics -->
<div class="row d-flex mt-3">
<?php if($activity[0]["activity_type"] == 1 || $activity[0]["activity_type"] == 2 || $activity[0]["activity_type"] == 3){ ?>
<div class="col">
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_detail_avgPower']; ?></span>
<br>
<?php if($activity[0]["average_power"]){
echo ($activity[0]["average_power"]); ?> W
<?php }else{
echo "No data";
} ?>
</div>
<div class="col border-start border-opacity-50">
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_detail_elevationGain']; ?></span>
<br>
<?php echo ($activity[0]["elevation_gain"]); ?> m
</div>
<div class="col border-start border-opacity-50">
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_detail_elevationLoss']; ?></span>
<br>
<?php echo ($activity[0]["elevation_loss"]); ?> m
</div>
<?php } ?>
<?php if($activity[0]["activity_type"] != 9 && $activity[0]["activity_type"] != 1){ ?>
<div class="col">
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_detail_avgSpeed']; ?></span>
<br>
<?php echo (number_format($activity[0]["average_speed"]*3.6)); ?> km/h
</div>
<div class="col border-start border-opacity-50">
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_detail_avgPower']; ?></span>
<br>
<?php if($activity[0]["average_power"]){
echo ($activity[0]["average_power"]); ?> W
<?php }else{
echo "No data";
} ?>
</div>
<div class="col border-start border-opacity-50">
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_detail_elevationLoss']; ?></span>
<br>
<?php echo $activity[0]["elevation_loss"]; ?> m
</div>
<?php } ?>
<div>
<!-- Map -->
<div class="mt-3 mb-3" id="map" style="height: 500px"></div>
<script>
// JavaScript code to create the map for this activity
var waypoints = <?php echo json_encode($activity[0]['waypoints']); ?>;
var mapId = "map";
var map = L.map(mapId, {
//dragging: false, // Disable panning
//touchZoom: false, // Disable touch zoom
//scrollWheelZoom: false, // Disable scroll wheel zoom
//zoomControl: false // Remove zoom control buttons
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
}).addTo(map);
var latlngs = waypoints.map(function(waypoint) {
return [waypoint.lat, waypoint.lon];
});
L.polyline(latlngs, { color: 'blue' }).addTo(map);
// Calculate the bounds of the polyline and fit the map to those bounds
var bounds = L.latLngBounds(latlngs);
map.fitBounds(bounds);
// Add green dot for the first waypoint
L.marker([waypoints[0].lat, waypoints[0].lon], { icon: L.divIcon({ className: 'bg-success dot' }) }).addTo(map);
// Add red dot for the last waypoint
L.marker([waypoints[waypoints.length - 1].lat, waypoints[waypoints.length - 1].lon], { icon: L.divIcon({ className: 'bg-danger dot' }) }).addTo(map);
</script>
<!-- gear -->
<hr class="mb-2 mt-2">
<div class="d-flex justify-content-between align-items-center">
<p class="pt-2">
<span class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_gear_title']; ?></span>
<br>
<?php if($activity[0]["activity_type"] == 1){ echo '<i class="fa-solid fa-person-running"></i>'; }else{ if($activity[0]["activity_type"] == 4 || $activity[0]["activity_type"] == 5 || $activity[0]["activity_type"] == 6 || $activity[0]["activity_type"] == 7 || $activity[0]["activity_type"] == 8){ echo '<i class="fa-solid fa-person-biking"></i>'; }else{ if($activity[0]["activity_type"] == 9){ echo '<i class="fa-solid fa-person-swimming"></i>'; } } } ?>
<?php if($activity[0]["gear_id"] == null){ ?>
<?php echo $translationsActivitiesActivity['activity_gear_notset']; ?>
<?php }else{ ?>
<?php echo $activityGear[0]['nickname']; ?>
<?php } ?>
</p>
<div class="justify-content-end">
<?php if($activity[0]["gear_id"] == null){ ?>
<!-- add gear zone -->
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#addGearToActivityModal"><i class="fa-solid fa-plus"></i></a>
<!-- modal -->
<div class="modal fade" id="addGearToActivityModal" tabindex="-1" aria-labelledby="addGearToActivityModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="addGearToActivityModal"><?php echo $translationsActivitiesActivity['activity_gear_addGear_title']; ?></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="../activities/activity.php?activityID=<?php echo $activity[0]["id"]; ?>&addGearToActivity=1" method="post" enctype="multipart/form-data">
<div class="modal-body">
<!-- gear type fields -->
<label for="gearIDAdd"><b>* <?php echo $translationsActivitiesActivity['activity_gear_addGear_label']; ?></b></label>
<select class="form-control" name="gearIDAdd">
<?php foreach($activityGearOptions as $option) { ?>
<option value="<?php echo $option["id"]; ?>"><?php echo $option["nickname"]; ?></option>
<?php } ?>
</select required>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo $translationsTemplateTop['template_top_global_close']; ?></button>
<button type="submit" class="btn btn-success" name="addGearToActivity"><?php echo $translationsActivitiesActivity['activity_gear_addGear_submit']; ?></button>
</div>
</form>
</div>
</div>
</div>
<?php }else{ ?>
<!-- Edit zone -->
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#editGearActivityModal"><i class="fa-regular fa-pen-to-square"></i></a>
<!-- modal -->
<div class="modal fade" id="editGearActivityModal" tabindex="-1" aria-labelledby="editGearActivityModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="editGearActivityModal"><?php echo $translationsActivitiesActivity['activity_gear_editGear_title']; ?></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="../activities/activity.php?activityID=<?php echo $activity[0]["id"]; ?>&editGearActivity=1" method="post" enctype="multipart/form-data">
<div class="modal-body">
<!-- gear type fields -->
<label for="gearIDEdit"><b>* <?php echo $translationsActivitiesActivity['activity_gear_addGear_label']; ?></b></label>
<select class="form-control" name="gearIDEdit">
<?php foreach($activityGearOptions as $option) { ?>
<option value="<?php echo $option["id"]; ?>"><?php echo $option["nickname"]; ?></option>
<?php } ?>
</select required>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo $translationsTemplateTop['template_top_global_close']; ?></button>
<button type="submit" class="btn btn-success" name="editGearActivity"><?php echo $translationsActivitiesActivity['activity_gear_editGear_submit']; ?></button>
</div>
</form>
</div>
</div>
</div>
<!-- Delete zone -->
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#deleteGearActivityModal"><i class="fa-solid fa-trash"></i></a>
<!-- Modal delete gear -->
<div class="modal fade" id="deleteGearActivityModal" tabindex="-1" aria-labelledby="deleteGearActivityModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="deleteGearActivityModal"><?php echo $translationsActivitiesActivity['activity_gear_deleteGear_title']; ?></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<?php echo $translationsActivitiesActivity['activity_gear_deleteGear_body']; ?> <b><?php echo $activityGear[0]['nickname']; ?></b>?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo $translationsTemplateTop['template_top_global_close']; ?></button>
<a type="button" class="btn btn-danger" href="../activities/activity.php?activityID=<?php echo $activity[0]["id"]; ?>&deleteGearActivity=1"><?php echo $translationsActivitiesActivity['activity_gear_deleteGear_title']; ?></a>
</div>
</div>
</div>
</div>
<?php } ?>
</div>
</div>
<!-- waypoints graph -->
<hr class="mb-2 mt-2">
<div class="row">
<!--<h2 class="mb-3"><?php echo $translationsActivitiesActivity['activity_dataGraph_title']; ?></h2>-->
<div class="col-md-2">
<p><?php echo $translationsActivitiesActivity['activity_dataGraph_dataSelection']; ?></p>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="hrCheckbox" checked>
<label class="form-check-label" for="hrCheckbox"><?php echo $translationsActivitiesActivity['activity_dataGraph_hr']; ?></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="cadenceCheckbox">
<label class="form-check-label" for="cadenceCheckbox"><?php echo $translationsActivitiesActivity['activity_dataGraph_cad']; ?></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="powerCheckbox">
<label class="form-check-label" for="powerCheckbox"><?php echo $translationsActivitiesActivity['activity_dataGraph_power']; ?></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="elevationCheckbox">
<label class="form-check-label" for="elevationCheckbox"><?php echo $translationsActivitiesActivity['activity_dataGraph_ele']; ?></label>
</div>
<?php if($activity[0]["activity_type"] == 4 || $activity[0]["activity_type"] == 5 || $activity[0]["activity_type"] == 6 || $activity[0]["activity_type"] == 7 || $activity[0]["activity_type"] == 8){ ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="velocityCheckbox">
<label class="form-check-label" for="velocityCheckbox"><?php echo $translationsActivitiesActivity['activity_dataGraph_vel']; ?></label>
</div>
<?php }else{ ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="paceCheckbox">
<label class="form-check-label" for="paceCheckbox"><?php echo $translationsActivitiesActivity['activity_dataGraph_pace']; ?></label>
</div>
<?php } ?>
</div>
<div class="col">
<canvas id="dataChart" height="100"></canvas>
<p class="fw-lighter"><?php echo $translationsActivitiesActivity['activity_dataGraph_downsampleDataInfo']; ?></p>
</div>
</div>
<script>
var ctx = document.getElementById('dataChart').getContext('2d');
var activityType = <?php echo $activity[0]["activity_type"]; ?>;
const downsampledDataHr = downsampleData(<?php echo json_encode($hrData); ?>, 200);
const downsampledDataCad = downsampleData(<?php echo json_encode($cadData); ?>, 200);
const downsampledDataPower = downsampleData(<?php echo json_encode($powerData); ?>, 200);
const downsampledDataEle = downsampleData(<?php echo json_encode($eleData); ?>, 200);
if (activityType === 4 || activityType === 5 || activityType === 6 || activityType === 7 || activityType === 8){
const downsampledDataVel = downsampleData(<?php echo json_encode($velData); ?>, 200);
var selectedData = {
hr: true,
cadence: false,
power: false,
elevation: false,
velocity: false
};
var data = {
hr: downsampledDataHr,
cadence: downsampledDataCad,
power: downsampledDataPower,
elevation: downsampledDataEle,
velocity: downsampledDataVel
};
}else{
const downsampledDataPace = downsampleData(<?php echo json_encode($paceData); ?>, 200);
var selectedData = {
hr: true,
cadence: false,
power: false,
elevation: false,
pace: false
};
var data = {
hr: downsampledDataHr,
cadence: downsampledDataCad,
power: downsampledDataPower,
elevation: downsampledDataEle,
pace: downsampledDataPace
};
}
var timestamps = data.hr.map(function(value, index) {
return index;
});
var dataChart = new Chart(ctx, {
type: 'line',
data: {
labels: timestamps,
datasets: []
},
options: {
responsive: true,
maintainAspectRatio: true,
scales: {
x: {
display: false
},
y: {
beginAtZero: false,
title: {
display: false
}
},
},
plugins: {
legend: {
display: true
},
tooltips: {
enabled: true,
mode: 'index',
intersect: false,
}
},
},
});
function downsampleData(data, threshold) {
if (data.length <= threshold) {
return data;
}
const factor = Math.ceil(data.length / threshold);
const downsampledData = [];
for (let i = 0; i < data.length; i += factor) {
const chunk = data.slice(i, i + factor);
const average = chunk.reduce((a, b) => a + b) / chunk.length;
downsampledData.push(average);
}
return downsampledData;
}
function formatPace(pace) {
const minutes = Math.floor(pace); // Extract whole minutes
let decimalFraction = pace - minutes; // Get the decimal fraction
let seconds = Math.round(decimalFraction * 60); // Convert the fraction to seconds
return `${minutes}:${seconds.toString().padStart(2, '0')} min/km`;
}
function updateChart() {
// Determine which data series to display
var datasets = [];
if (selectedData.hr) {
datasets.push({
label: 'Heart Rate',
data: data.hr,
borderColor: 'rgb(255, 0, 0)',
fill: false,
});
}
if (selectedData.cadence) {
datasets.push({
label: 'Cadence',
data: data.cadence,
borderColor: 'rgb(75, 192, 192)',
fill: false,
});
}
if (selectedData.power) {
datasets.push({
label: 'Power (W)',
data: data.power,
borderColor: 'rgb(0, 0, 255)',
fill: false,
});
}
if (selectedData.elevation) {
datasets.push({
label: 'Elevation',
data: data.elevation,
borderColor: 'rgb(0, 255, 0)',
fill: false,
});
}
if (activityType === 4 || activityType === 5 || activityType === 6 || activityType === 7|| activityType === 8){
if (selectedData.velocity) {
datasets.push({
label: 'Velocity (km/h)',
data: data.velocity,
borderColor: 'rgb(255, 255, 0)',
fill: false,
});
}
}else{
if (activityType === 1 || activityType === 2 || activityType === 3){
if (selectedData.pace) {
datasets.push({
label: 'Pace (min/km)',
data: data.pace,
borderColor: 'rgb(255, 255, 0)',
fill: false,
});
}
}else{
if (selectedData.pace) {
datasets.push({
label: 'Pace (min/100m)',
data: data.pace,
borderColor: 'rgb(255, 255, 0)',
fill: false,
});
}
}
}
// Update the chart
dataChart.data.datasets = datasets;
dataChart.options.scales.y.title.display = datasets.length === 1; // Show Y-axis label if only one dataset is selected
dataChart.update();
}
// Listen for checkbox changes
document.getElementById('hrCheckbox').addEventListener('change', function() {
selectedData.hr = this.checked;
updateChart();
});
document.getElementById('cadenceCheckbox').addEventListener('change', function() {
selectedData.cadence = this.checked;
updateChart();
});
document.getElementById('powerCheckbox').addEventListener('change', function() {
selectedData.power = this.checked;
updateChart();
});
document.getElementById('elevationCheckbox').addEventListener('change', function() {
selectedData.elevation = this.checked;
updateChart();
});
if (activityType === 4 || activityType === 5 || activityType === 6 || activityType === 7 || activityType === 8){
document.getElementById('velocityCheckbox').addEventListener('change', function() {
selectedData.velocity = this.checked;
updateChart();
});
}else{
document.getElementById('paceCheckbox').addEventListener('change', function() {
selectedData.pace = this.checked;
updateChart();
});
}
// Initial chart update
updateChart();
</script>
<!-- <script>
var ctx = document.getElementById('hrChart').getContext('2d');
var hrData = <?php echo json_encode($hrData); ?>;
var timestamps = hrData.map(function(value, index) {
return index;
});
var hrChart = new Chart(ctx, {
type: 'line',
data: {
labels: timestamps,
datasets: [{
label: 'Heart Rate',
data: hrData,
borderColor: 'rgb(75, 192, 192)',
fill: false,
}],
},
options: {
responsive: true,
maintainAspectRatio: true,
scales: {
x: {
display: false, // Hide x-axis
},
y: {
beginAtZero: true,
title: {
display: true,
text: 'Heart Rate',
},
},
},
plugins: {
legend: {
display: false, // Hide legend
},
tooltips: {
enabled: true, // Enable tooltips
mode: 'index',
intersect: false,
}
},
},
});
</script> -->
<div>
<br class="d-lg-none">
<button onclick="window.history.back();" type="button" class="w-100 btn btn-primary d-lg-none"><?php echo $translationsTemplateTop['template_top_global_back']; ?></button>
</div>
</div>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Bottom.php" ?>

255
frontend/gear/gear.php Normal file
View File

@@ -0,0 +1,255 @@
<?php
if(!isset($_SESSION)){
session_start();
}
require_once $_SERVER['DOCUMENT_ROOT']."/inc/sqlFunctions.php";
$page="gear";
$gear = [];
$editGearAction = -9000;
$deleteGearAction = -9000;
if(!isLogged()){
header("Location: ../login.php");
}
if(!isTokenValid($_SESSION["token"])){
header("Location: ../logout.php?sessionExpired=1");
}
// Load the language file based on the user's preferred language
switch ($_SESSION["preferred_language"]) {
case 'en':
$translationsGearGear = include $_SERVER['DOCUMENT_ROOT'].'/lang/gear/gear/en.php';
break;
case 'pt':
$translationsGearGear = include $_SERVER['DOCUMENT_ROOT'].'/lang/gear/gear/pt.php';
break;
// ...
default:
$translationsGearGear = include $_SERVER['DOCUMENT_ROOT'].'/lang/gear/gear/en.php';
}
/* Edit action */
if (isset($_POST["editGear"]) && $_GET["editGear"] == 1) {
if(empty(trim($_POST["gearBrandEdit"]))){
$_POST["gearBrandEdit"] = NULL;
}
if(empty(trim($_POST["gearModelEdit"]))){
$_POST["gearModelEdit"] = NULL;
}
$editGearAction = editGear($_GET["gearID"], urlencode(trim($_POST["gearBrandEdit"])), urlencode(trim($_POST["gearModelEdit"])), urlencode(trim($_POST["gearNicknameEdit"])), $_POST["gearTypeEdit"], date("Y-m-d H:i:s", strtotime($_POST["gearDateEdit"] . " 00:00:00")), $_POST["gearIsActiveEdit"]);
}
/* Delete gear */
if(isset($_GET["deleteGear"]) && $_GET["deleteGear"] == 1){
$deleteGearAction = deleteGear($_GET["gearID"]);
if($deleteGearAction == 0){
header("Location: ../gear/gears.php?deleteGear=1");
}
}
$gear = getGearFromId($_GET["gearID"]);
if ($gear == NULL){
header("Location: ../gear/gears.php?invalidGear=1");
}
$gearActivities = getGearActivities($_GET["gearID"]);
$gearTotalDistance = 0;
foreach($gearActivities as $activity){
$gearTotalDistance += $activity["distance"];
}
?>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Top.php" ?>
<div class="container mt-4">
<h1><?php echo $gear[0]["nickname"]; ?></h1>
</div>
<div class="container mt-4">
<!-- Error banners -->
<?php if($editGearAction == -1 || $editGearAction == -2 || $deleteGearAction == -1 || $deleteGearAction == -2){ ?>
<div class="alert alert-danger alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-exclamation me-1"></i>
<div>
<?php if($editGearAction == -1 || $deleteGearAction == -1){ ?>
API ERROR | <?php echo $translationsGearGear['gear_API_error_-1']; ?> (-1).
<?php }else{ ?>
<?php if($editGearAction == -2 || $deleteGearAction == -2){ ?>
API ERROR | <?php echo $translationsGearGear['gear_API_error_-2']; ?> (-2).
<?php } ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<!-- Success banners -->
<?php if($editGearAction == 0){ ?>
<div class="alert alert-success alert-dismissible d-flex align-items-center" role="alert">
<div>
<i class="fa-regular fa-circle-check me-1"></i>
<?php if($editGearAction == 0){ ?>
<?php echo $translationsGearGear['gear_success_gearEdited']; ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<div class="row row-gap-3">
<!-- left column -->
<div class="col-lg-3 col-md-12">
<!-- Gear photo -->
<div class="justify-content-center align-items-center d-flex">
<img src=<?php if($gear[0]["gear_type"] == 1){ echo ("../img/avatar/bicycle1.png"); }else{ if($gear[0]["gear_type"] == 2){ echo ("../img/avatar/running_shoe1.png"); }else{ echo ("../img/avatar/wetsuit1.png"); }} ?> alt="gearPicture" width="180" height="180">
<!--<img src=<?php if($gear[0]["gear_type"] == 1){ echo ("../img/avatar/bicycle1.png"); }else{ if($gear[0]["gear_type"] == 2){ echo ("../img/avatar/running_shoe1.png"); }else{ echo ("../img/avatar/wetsuit1.png"); }} ?> alt="gearPicture" class="rounded-circle" width="180" height="180">-->
</div>
<br>
<div class="vstack justify-content-center align-items-center d-flex">
<!-- badges -->
<div class="hstack justify-content-center">
<?php if($gear[0]["is_active"] == 1){ ?>
<span class="badge bg-success-subtle border border-success-subtle text-success-emphasis rounded-pill align-middle"><?php echo $translationsGearGear['gear_gear_infoZone_isactive']; ?></span>
<?php }else{ ?>
<span class="badge bg-danger-subtle border border-danger-subtle text-danger-emphasis rounded-pill align-middle"><?php echo $translationsGearGear['gear_gear_infoZone_isinactive']; ?></span>
<?php } ?>
<?php if($gear[0]["gear_type"] == 1){ ?>
<span class="ms-2 badge bg-primary-subtle border border-primary-subtle text-primary-emphasis rounded-pill align-middle"><?php echo $translationsGearGear['gear_gear_infoZone_gearisbike']; ?></span>
<?php }else{
if($gear[0]["gear_type"] == 2){ ?>
<span class="ms-2 badge bg-primary-subtle border border-primary-subtle text-primary-emphasis rounded-pill align-middle"><?php echo $translationsGearGear['gear_gear_infoZone_gearisshoe']; ?></span>
<?php }else{ ?>
<span class="ms-2 badge bg-primary-subtle border border-primary-subtle text-primary-emphasis rounded-pill align-middle"><?php echo $translationsGearGear['gear_gear_infoZone_geariswetsuit']; ?></span>
<?php } ?>
<?php } ?>
</div>
<!-- edit gear zone -->
<a class="mt-2 w-100 btn btn-primary" href="#" role="button" data-bs-toggle="modal" data-bs-target="#editGearModal"><?php echo $translationsGearGear['gear_gear_infoZone_editbutton']; ?></a>
<!-- Modal edit gear -->
<div class="modal fade" id="editGearModal" tabindex="-1" aria-labelledby="editGearModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="editGearModal"><?php echo $translationsGearGear['gear_gear_infoZone_editbutton']; ?></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="../gear/gear.php?gearID=<?php echo ($gear[0]["id"]); ?>&editGear=1" method="post" enctype="multipart/form-data">
<div class="modal-body">
<!-- brand fields -->
<label for="gearBrandEdit"><b><?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_brandLabel']; ?></b></label>
<input class="form-control" type="text" name="gearBrandEdit" placeholder="<?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_brandPlaceholder']; ?>" maxlength="45" value="<?php echo($gear[0]["brand"]); ?>">
<!-- model fields -->
<label for="gearModelEdit"><b><?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_modelLabel']; ?></b></label>
<input class="form-control" type="text" name="gearModelEdit" placeholder="<?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_modelPlaceholder']; ?>" maxlength="45" value="<?php echo($gear[0]["model"]); ?>">
<!-- nickname fields -->
<label for="gearNicknameEdit"><b><?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_nicknameLabel']; ?></b></label>
<input class="form-control" type="text" name="gearNicknameEdit" placeholder="<?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_nicknamePlaceholder']; ?>" maxlength="45" value="<?php echo($gear[0]["nickname"]); ?>">
<!-- gear type fields -->
<label for="gearTypeEdit"><b>* <?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_gearTypeLabel']; ?></b></label>
<select class="form-control" name="gearTypeEdit">
<option value="1" <?php if($gear[0]["gear_type"] == 1){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_gearTypeOption1']; ?></option>
<option value="2" <?php if($gear[0]["gear_type"] == 2){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_gearTypeOption2']; ?></option>
<option value="3" <?php if($gear[0]["gear_type"] == 3){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_gearTypeOption3']; ?></option>
</select required>
<!-- date fields -->
<label for="gearDateEdit"><b><?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_dateLabel']; ?></b></label>
<input class="form-control" type="date" name="gearDateEdit" placeholder="<?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_datePlaceholder']; ?>" value="<?php echo date("Y-m-d", strtotime($gear[0]["created_at"])); ?>" required>
<!-- gear is_active fields -->
<label for="gearIsActiveEdit"><b>* <?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_gearIsActiveLabel']; ?></b></label>
<select class="form-control" name="gearIsActiveEdit">
<option value="1" <?php if($gear[0]["is_active"] == 1){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_gearIsActiveOption1']; ?></option>
<option value="2" <?php if($gear[0]["is_active"] == 2){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_infoZone_modal_editGear_gearIsActiveOption2']; ?></option>
</select required>
* <?php echo $translationsTemplateTop['template_top_global_requiredFields']; ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo $translationsTemplateTop['template_top_global_close']; ?></button>
<button type="submit" class="btn btn-success" name="editGear"><?php echo $translationsGearGear['gear_gear_infoZone_editbutton']; ?></button>
</div>
</form>
</div>
</div>
</div>
<!-- delete gear zone -->
<a class="mt-2 w-100 btn btn-danger <?php if(count($gearActivities) != 0){ echo "disabled"; } ?>" href="#" role="button" data-bs-toggle="modal" data-bs-target="#deleteGearModal" <?php if(count($gearActivities) != 0){ echo 'aria-disabled="true"' ; } ?>><?php echo $translationsGearGear['gear_gear_infoZone_deletebutton']; ?></a>
<!-- Modal delete gear -->
<div class="modal fade" id="deleteGearModal" tabindex="-1" aria-labelledby="deleteGearModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="deleteGearModal"><?php echo $translationsGearGear['gear_gear_infoZone_deletebutton']; ?></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<?php echo $translationsGearGear['gear_gear_infoZone_modal_deleteGear_body']; ?> <b><?php echo ($gear[0]["nickname"]); ?></b><span>?</span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo $translationsTemplateTop['template_top_global_close']; ?></button>
<a type="button" class="btn btn-danger" href="../gear/gear.php?gearID=<?php echo ($gear[0]["id"]); ?>&deleteGear=1"><?php echo $translationsGearGear['gear_gear_infoZone_deletebutton']; ?></a>
</div>
</div>
</div>
</div>
<!-- details -->
<div class="vstack align-items-center">
<span class="mt-2"><strong><?php echo $translationsGearGear['gear_gear_infoZone_distance']; ?>: </strong><?php echo number_format($gearTotalDistance/1000,2); ?> km</span>
<?php if(isset($gear[0]["brand"])){ ?>
<span class="mt-2"><strong><?php echo $translationsGearGear['gear_gear_infoZone_brand']; ?>: </strong><?php echo $gear[0]["brand"]; ?></span>
<?php } ?>
<?php if(isset($gear[0]["model"])){ ?>
<span class="mt-2"><strong><?php echo $translationsGearGear['gear_gear_infoZone_model']; ?>: </strong><?php echo $gear[0]["model"]; ?></span>
<?php } ?>
</div>
</div>
</div>
<!-- right column -->
<div class="col">
<div>
<!-- Gear components -->
<!-- Last 10 gear activities -->
<hr class="mb-2 mt-2 d-sm-none d-block">
<div class="hstack align-items-baseline">
<h5><?php echo $translationsGearGear['gear_gear_gearActivities_title']; ?></h5>
<h7 class="ms-1"><?php echo $translationsGearGear['gear_gear_gearActivities_number']; ?></h7>
</div>
<?php if(count($gearActivities) == 0){ ?>
<div class="alert alert-warning alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-info me-1"></i>
<div>
<?php echo $translationsGearGear['gear_gear_gearActivities_noactivities']; ?>.
</div>
</div>
<?php }else{ ?>
<ul class="list-group list-group-flush">
<?php for ($x = 0; $x < 10; $x+=1) { ?>
<?php if($x < count($gearActivities)){ ?>
<li class="vstack list-group-item d-flex justify-content-between">
<a href="../activities/activity.php?activityID=<?php echo $gearActivities[$x]["id"];?>"><?php echo $gearActivities[$x]["name"];?></a>
<span><strong><?php echo $translationsGearGear['gear_gear_gearActivities_datelabel']; ?>: </strong><?php echo (new DateTime($gearActivities[$x]["start_time"]))->format("d/m/y"); ?>@<?php echo (new DateTime($gearActivities[$x]["start_time"]))->format("H:i"); ?></span>
</li>
<?php } ?>
<?php } ?>
</ul>
<?php } ?>
</div>
</div>
</div>
<div>
<br>
<button onclick="window.history.back();" type="button" class="w-100 btn btn-primary d-lg-none"><?php echo $translationsTemplateTop['template_top_global_back']; ?></button>
</div>
</div>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Bottom.php" ?>

349
frontend/gear/gear_old.php Normal file
View File

@@ -0,0 +1,349 @@
<?php
if(!isset($_SESSION)){
session_start();
}
require_once $_SERVER['DOCUMENT_ROOT']."/inc/sqlFunctions.php";
$page="gear";
$addGearAction = -9000;
$editGearAction = -9000;
$deleteGearAction = -9000;
$numGear = 0;
$gears = [];
$pageNumber = 1;
$numRecords = 5;
if(!isLogged()){
header("Location: ../login.php");
}
if(!isTokenValid($_SESSION["token"])){
header("Location: ../logout.php?sessionExpired=1");
}
// Load the language file based on the user's preferred language
switch ($_SESSION["preferred_language"]) {
case 'en':
$translationsGearGear = include $_SERVER['DOCUMENT_ROOT'].'/lang/gear/en.php';
break;
case 'pt':
$translationsGearGear = include $_SERVER['DOCUMENT_ROOT'].'/lang/gear/pt.php';
break;
// ...
default:
$translationsGearGear = include $_SERVER['DOCUMENT_ROOT'].'/lang/gear/en.php';
}
/* Add action */
if(isset($_POST["addGear"]) && $_GET["addGear"] == 1){
if(empty(trim($_POST["gearBrandAdd"]))){
$_POST["gearBrandAdd"] = NULL;
}
if(empty(trim($_POST["gearModelAdd"]))){
$_POST["gearModelAdd"] = NULL;
}
$addGearAction = newGear(urlencode(trim($_POST["gearBrandAdd"])), urlencode(trim($_POST["gearModelAdd"])), urlencode(trim($_POST["gearNicknameAdd"])), $_POST["gearTypeAdd"], $_SESSION["id"], $_POST["gearDateAdd"]);
}
/* Edit action */
if (isset($_POST["editGear"]) && $_GET["editGear"] == 1) {
if(empty(trim($_POST["gearBrandEdit"]))){
$_POST["gearBrandEdit"] = NULL;
}
if(empty(trim($_POST["gearModelEdit"]))){
$_POST["gearModelEdit"] = NULL;
}
$editGearAction = editGear($_GET["gearID"], urlencode(trim($_POST["gearBrandEdit"])), urlencode(trim($_POST["gearModelEdit"])), urlencode(trim($_POST["gearNicknameEdit"])), $_POST["gearTypeEdit"], $_POST["gearDateEdit"], $_POST["gearIsActiveEdit"]);
}
/* Delete gear */
if(isset($_GET["deleteGear"]) && $_GET["deleteGear"] == 1){
$deleteGearAction = deleteGear($_GET["gearID"]);
}
if(isset($_GET["pageNumber"])){
$pageNumber = $_GET["pageNumber"];
}
if(!isset($_POST["gearSearch"])){
$gears = getGearPagination($pageNumber, $numRecords);
$numGear = numGear();
$total_pages = ceil($numGear / $numRecords);
}else{
$gears = getGearFromNickname(urlencode(trim($_POST["gearNickname"])));
if($gears == NULL){
$numGear=0;
}else{
$numGear=1;
}
}
?>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Top.php" ?>
<div class="container mt-4">
<h1><?php echo $translationsGearGear['gear_title']; ?></h1>
</div>
<div class="container mt-4">
<!-- Error banners -->
<?php if($gears == -1 || $gears == -2 || $editGearAction == -1 || $editGearAction == -2 || $editGearAction == -3 || $deleteGearAction == -1 || $deleteGearAction == -2 || $deleteGearAction == -3 || $addGearAction == -1 || $addGearAction == -2 || $addGearAction == -3){ ?>
<div class="alert alert-danger alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-exclamation me-1"></i>
<div>
<?php if($gears == -1 || $addGearAction == -1 || $editGearAction == -1 || $deleteGearAction == -1){ ?>
API ERROR | <?php echo $translationsGearGear['gear_gear_API_error_-1']; ?> (-1).
<?php }else{ ?>
<?php if($gears == -2 || $addGearAction == -2 || $editGearAction == -2 || $deleteGearAction == -2){ ?>
API ERROR | <?php echo $translationsGearGear['gear_gear_API_error_-2']; ?> (-2).
<?php }else{ ?>
<?php if($editGearAction == -3){ ?>
<?php echo $translationsGearGear['gear_gear_error_editGear_-3']; ?> (-3).
<?php }else{ ?>
<?php if($addGearAction == -3){ ?>
<?php echo $translationsGearGear['gear_gear_error_addGear_-3']; ?> (-3).
<?php } ?>
<?php } ?>
<?php } ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<!-- Info banners -->
<?php if($gears == NULL){ ?>
<div class="alert alert-warning alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-triangle-exclamation me-1"></i>
<div>
<?php if($users == NULL){ ?>
<?php echo $translationsGearGear['gear_gear_error_searchGear_NULL']; ?> (NULL).
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<!-- Success banners -->
<?php if($addGearAction == 0 || $editGearAction == 0 || $deleteGearAction == 0){ ?>
<div class="alert alert-success alert-dismissible d-flex align-items-center" role="alert">
<div>
<i class="fa-regular fa-circle-check me-1"></i>
<?php if($addGearAction == 0){ ?>
<?php echo $translationsGearGear['gear_gear_success_gearAdded']; ?>
<?php }else{ ?>
<?php if($editGearAction == 0){ ?>
<?php echo $translationsGearGear['gear_gear_success_gearEdited']; ?>
<?php }else{ ?>
<?php if($deleteGearAction == 0){ ?>
<?php echo $translationsGearGear['gear_gear_success_gearDeleted']; ?>
<?php } ?>
<?php } ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<div class="row row-gap-3">
<div class="col-lg-4 col-md-12">
<!-- Add gear zone -->
<p><?php echo $translationsGearGear['gear_gear_buttonLabel_addGear']; ?></p>
<a class="w-100 btn btn-primary" href="#" role="button" data-bs-toggle="modal" data-bs-target="#addGearModal"><?php echo $translationsGearGear['gear_gear_button_addGear']; ?></a>
<!-- Modal add gear -->
<div class="modal fade" id="addGearModal" tabindex="-1" aria-labelledby="addGearModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="addGearModal"><?php echo $translationsGearGear['gear_gear_modal_addGear_title']; ?></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="../gear/gear.php?addGear=1" method="post" enctype="multipart/form-data">
<div class="modal-body">
<!-- brand fields -->
<label for="gearBrandAdd"><b><?php echo $translationsGearGear['gear_gear_modal_addEditGear_brandLabel']; ?></b></label>
<input class="form-control" type="text" name="gearBrandAdd" placeholder="<?php echo $translationsGearGear['gear_gear_modal_addEditGear_brandPlaceholder']; ?>" maxlength="45" value="<?php echo($_POST["gearBrandAdd"]); ?>">
<!-- model fields -->
<label for="gearModelAdd"><b><?php echo $translationsGearGear['gear_gear_modal_addEditGear_modelLabel']; ?></b></label>
<input class="form-control" type="text" name="gearModelAdd" placeholder="<?php echo $translationsGearGear['gear_gear_modal_addEditGear_modelPlaceholder']; ?>" maxlength="45" value="<?php echo($_POST["gearModelAdd"]); ?>">
<!-- nickname fields -->
<label for="gearNicknameAdd"><b><?php echo $translationsGearGear['gear_gear_modal_addEditGear_nicknameLabel']; ?></b></label>
<input class="form-control" type="text" name="gearNicknameAdd" placeholder="<?php echo $translationsGearGear['gear_gear_modal_addEditGear_nicknamePlaceholder']; ?>" maxlength="45" value="<?php echo($_POST["gearNicknameAdd"]); ?>">
<!-- gear type fields -->
<label for="gearTypeAdd"><b>* <?php echo $translationsGearGear['gear_gear_modal_addEditUser_gearTypeLabel']; ?></b></label>
<select class="form-control" name="gearTypeAdd">
<option value="1" <?php if($_POST["gearTypeAdd"] == 1){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_modal_addEditUser_gearTypeOption1']; ?></option>
<option value="2" <?php if($_POST["gearTypeAdd"] == 2){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_modal_addEditUser_gearTypeOption2']; ?></option>
<option value="3" <?php if($_POST["gearTypeAdd"] == 3){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_modal_addEditUser_gearTypeOption3']; ?></option>
</select required>
<!-- date fields -->
<label for="gearDateAdd"><b><?php echo $translationsGearGear['gear_gear_modal_addEditGear_dateLabel']; ?></b></label>
<input class="form-control" type="date" name="gearDateAdd" placeholder="<?php echo $translationsGearGear['gear_gear_modal_addEditGear_datePlaceholder']; ?>" value="<?php echo($_POST["gearDateAdd"]); ?>" required>
* <?php echo $translationsTemplateTop['template_top_global_requiredFields']; ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo $translationsTemplateTop['template_top_global_close']; ?></button>
<button type="submit" class="btn btn-success" name="addGear"><?php echo $translationsGearGear['gear_gear_modal_addGear_title']; ?></button>
</div>
</form>
</div>
</div>
</div>
<br>
<p><?php echo $translationsGearGear['gear_gear_buttonLabel_searchGear']; ?></p>
<form action="../gear/gear.php" method="post">
<div class="mb-3">
<!--<label for="userUsername"><b>Username</b></label>-->
<input class="form-control" type="text" name="gearNickname" placeholder="<?php echo $translationsGearGear['gear_gear_form_searchGear_nicknamePlaceholder']; ?>" required>
</div>
<button class="w-100 btn btn-success" type="submit" name="gearSearch"><?php echo $translationsGearGear['gear_gear_button_searchGear']; ?></button>
</form>
<?php if(isset($_POST["gearSearch"])){ ?>
<br>
<a class="w-100 btn btn-primary" href="../gear/gear.php" role="button"><?php echo $translationsTemplateTop['template_top_global_button_listAll']; ?></a>
<?php } ?>
</div>
<div class="col">
<?php if($gears == -1 || $numGear == -1 || $gears == -2){ ?>
<div class="alert alert-danger alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-exclamation"></i>
<div>
<?php if($gears == -1 || $numGear == -1 || $gears == -2){ ?>
<?php echo $translationsGearGear['gear_gear_error_listGear_-1-2']; ?> (-1/-2).
<?php } ?>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php }else{ ?>
<!-- Info banners -->
<?php if($gears == -3){ ?>
<div class="alert alert-warning alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-triangle-exclamation"></i>
<div>
<?php if($gears == -3){ ?>
<?php echo $translationsGearGear['gear_gear_error_listGear_-3']; ?> (-3).
<?php } ?>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php }else{ ?>
<p><?php echo $translationsGearGear['gear_gear_list_title1']; ?> <?php echo ($numGear); ?> <?php echo $translationsGearGear['gear_gear_list_title2']; ?> (<?php echo $numRecords; ?> <?php echo $translationsGearGear['gear_gear_list_title3']; ?>:</p>
<ul class="list-group list-group-flush">
<?php foreach ($gears as $gear) { ?>
<li class="list-group-item d-flex justify-content-between">
<div class="d-flex align-items-center">
<img src=<?php if($gear["gear_type"] == 1){ echo ("../img/avatar/male1.png"); }else{ if($gear["gear_type"] == 2){ echo ("../img/avatar/male1.png"); }else{ echo ("../img/avatar/female1.png"); }} ?> alt="gearPicture" class="rounded-circle" width="55" height="55">
<div class="ms-3">
<div class="fw-bold">
<?php echo ($gear["nickname"]); ?>
</div>
<b><?php echo $translationsGearGear['gear_gear_gear_type']; ?></b><?php if($gear["gear_type"] == 1){ echo $translationsGearGear['gear_gear_modal_addEditUser_gearTypeOption1']; }else{ if($gear["gear_type"] == 2){ echo $translationsGearGear['gear_gear_modal_addEditUser_gearTypeOption2']; }else{ if($gear["gear_type"] == 3){ echo $translationsGearGear['gear_gear_modal_addEditUser_gearTypeOption3']; }}} ?>
</br>
<?php if($gear["is_active"] == 1){ ?>
<span class="badge bg-success-subtle border border-success-subtle text-success-emphasis align-middle"><?php echo $translationsGearGear['gear_gear_list_isactive']; ?></span>
<?php }else{ ?>
<span class="badge bg-danger-subtle border border-danger-subtle text-danger-emphasis align-middle"><?php echo $translationsGearGear['gear_gear_list_isinactive']; ?></span>
<?php } ?>
</div>
</div>
<div>
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#editGearModal<?php echo ($gear["id"]); ?>"><i class="fa-solid fa-pen-to-square"></i></a>
<!-- Modal edit user -->
<div class="modal fade" id="editGearModal<?php echo ($gear["id"]); ?>" tabindex="-1" aria-labelledby="editGearModal<?php echo ($gear["id"]); ?>" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="editGearModal<?php echo ($user["id"]); ?>"><?php echo $translationsGearGear['gear_gear_modal_editGear_title']; ?></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="../gear/gear.php?gearID=<?php echo ($gear["id"]); ?>&editGear=1" method="post" enctype="multipart/form-data">
<div class="modal-body">
<!-- brand fields -->
<label for="gearBrandEdit"><b><?php echo $translationsGearGear['gear_gear_modal_addEditGear_brandLabel']; ?></b></label>
<input class="form-control" type="text" name="gearBrandEdit" placeholder="<?php echo $translationsGearGear['gear_gear_modal_addEditGear_brandPlaceholder']; ?>" maxlength="45" value="<?php echo($gear["brand"]); ?>">
<!-- model fields -->
<label for="gearModelEdit"><b><?php echo $translationsGearGear['gear_gear_modal_addEditGear_modelLabel']; ?></b></label>
<input class="form-control" type="text" name="gearModelEdit" placeholder="<?php echo $translationsGearGear['gear_gear_modal_addEditGear_modelPlaceholder']; ?>" maxlength="45" value="<?php echo($gear["model"]); ?>">
<!-- nickname fields -->
<label for="gearNicknameEdit"><b><?php echo $translationsGearGear['gear_gear_modal_addEditGear_nicknameLabel']; ?></b></label>
<input class="form-control" type="text" name="gearNicknameEdit" placeholder="<?php echo $translationsGearGear['gear_gear_modal_addEditGear_nicknamePlaceholder']; ?>" maxlength="45" value="<?php echo($gear["nickname"]); ?>">
<!-- gear type fields -->
<label for="gearTypeEdit"><b>* <?php echo $translationsGearGear['gear_gear_modal_addEditUser_gearTypeLabel']; ?></b></label>
<select class="form-control" name="gearTypeEdit">
<option value="1" <?php if($gear["gear_type"] == 1){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_modal_addEditUser_gearTypeOption1']; ?></option>
<option value="2" <?php if($gear["gear_type"] == 2){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_modal_addEditUser_gearTypeOption2']; ?></option>
<option value="3" <?php if($gear["gear_type"] == 3){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_modal_addEditUser_gearTypeOption3']; ?></option>
</select required>
<!-- date fields -->
<label for="gearDateEdit"><b><?php echo $translationsGearGear['gear_gear_modal_addEditGear_dateLabel']; ?></b></label>
<input class="form-control" type="date" name="gearDateEdit" placeholder="<?php echo $translationsGearGear['gear_gear_modal_addEditGear_datePlaceholder']; ?>" value="<?php echo (new DateTime($gear["created_at"]))->format('Y-m-d'); ?>" required>
<!-- is active fields -->
<label for="gearIsActiveEdit"><b>* <?php echo $translationsGearGear['gear_gear_modal_editUser_gearIsActiveLabel']; ?></b></label>
<select class="form-control" name="gearIsActiveEdit">
<option value="1" <?php if($gear["is_active"] == 1){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_modal_editUser_gearIsActiveOption1']; ?></option>
<option value="0" <?php if($gear["is_active"] == 0){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGear['gear_gear_modal_editUser_gearIsActiveOption2']; ?></option>
</select required>
* <?php echo $translationsTemplateTop['template_top_global_requiredFields']; ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo $translationsTemplateTop['template_top_global_close']; ?></button>
<button type="submit" class="btn btn-success" name="editGear"><?php echo $translationsGearGear['gear_gear_modal_editGear_title']; ?></button>
</div>
</form>
</div>
</div>
</div>
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#deleteGearModal<?php echo ($gear["id"]); ?>"><i class="fa-solid fa-trash-can"></i></a>
<!-- Modal -->
<div class="modal fade" id="deleteGearModal<?php echo ($gear["id"]); ?>" tabindex="-1" aria-labelledby="deleteGearModal<?php echo ($gear["id"]); ?>" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="deleteGearModal<?php echo ($gear["id"]); ?>"><?php echo $translationsGearGear['gear_gear_modal_deleteGear_title']; ?></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<?php echo $translationsGearGear['gear_gear_modal_deleteGear_body']; ?> <b><?php echo ($gear["nickname"]); ?></b>?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo $translationsTemplateTop['template_top_global_close']; ?></button>
<a type="button" class="btn btn-danger" href="../gear/gear.php?gearID=<?php echo ($gear["id"]); ?>&deleteGear=1"><?php echo $translationsGearGear['gear_gear_modal_deleteGear_title']; ?></a>
</div>
</div>
</div>
</div>
</div>
</li>
<?php } ?>
</ul>
<?php if(!isset($_POST["gearSearch"])){ ?>
<br>
<nav>
<ul class="pagination justify-content-center">
<li class="page-item <?php if($pageNumber == 1){ echo "disabled"; } ?>"><a class="page-link" href="?pageNumber=1">«</a></li>
<?php for ($i = 1; $i <= $total_pages; $i++) { ?>
<li class="page-item <?php if($i == $pageNumber){ echo "active"; } ?>"><a class="page-link" href="?pageNumber=<?php echo ($i);?>"><?php echo ($i);?></a></li>
<?php } ?>
<li class="page-item <?php if($pageNumber == $total_pages){ echo "disabled"; } ?>"><a class="page-link" href="?pageNumber=<?php echo ($total_pages);?>">»</a></li>
</ul>
</nav>
<?php } ?>
<?php } ?>
<?php } ?>
</div>
</div>
<div>
<br>
<button onclick="window.history.back();" type="button" class="w-100 btn btn-primary d-lg-none"><?php echo $translationsTemplateTop['template_top_global_back']; ?></button>
</div>
</div>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Bottom.php" ?>

264
frontend/gear/gears.php Normal file
View File

@@ -0,0 +1,264 @@
<?php
if(!isset($_SESSION)){
session_start();
}
require_once $_SERVER['DOCUMENT_ROOT']."/inc/sqlFunctions.php";
$page="gears";
$addGearAction = -9000;
$numGears = 0;
$gears = [];
$pageNumber = 1;
$numRecords = 5;
if(!isLogged()){
header("Location: ../login.php");
}
if(!isTokenValid($_SESSION["token"])){
header("Location: ../logout.php?sessionExpired=1");
}
// Load the language file based on the user's preferred language
switch ($_SESSION["preferred_language"]) {
case 'en':
$translationsGearGears = include $_SERVER['DOCUMENT_ROOT'].'/lang/gear/gears/en.php';
break;
case 'pt':
$translationsGearGears = include $_SERVER['DOCUMENT_ROOT'].'/lang/gear/gears/pt.php';
break;
// ...
default:
$translationsGearGears = include $_SERVER['DOCUMENT_ROOT'].'/lang/gear/gears/en.php';
}
/* Add action */
if(isset($_POST["addGear"]) && $_GET["addGear"] == 1){
if(empty(trim($_POST["gearBrandAdd"]))){
$_POST["gearBrandAdd"] = NULL;
}
if(empty(trim($_POST["gearModelAdd"]))){
$_POST["gearModelAdd"] = NULL;
}
$addGearAction = newGear(urlencode(trim($_POST["gearBrandAdd"])), urlencode(trim($_POST["gearModelAdd"])), urlencode(trim($_POST["gearNicknameAdd"])), $_POST["gearTypeAdd"], $_POST["gearDateAdd"]);
}
if(isset($_GET["pageNumber"])){
$pageNumber = $_GET["pageNumber"];
}
if(!isset($_POST["gearSearch"])){
$gears = getGearPagination($pageNumber, $numRecords);
$numGears = numGears();
$total_pages = ceil($numGears / $numRecords);
}else{
$gears = getGearFromNickname(urlencode(trim($_POST["gearNickname"])));
if($gears == NULL){
$numGears=0;
}else{
$numGears=1;
}
}
?>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Top.php" ?>
<div class="container mt-4">
<h1><?php echo $translationsGearGears['gear_title']; ?></h1>
</div>
<div class="container mt-4">
<!-- Error banners -->
<?php if($gears == -1 || $gears == -2 || $addGearAction == -1 || $addGearAction == -2 || $addGearAction == -3){ ?>
<div class="alert alert-danger alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-exclamation me-1"></i>
<div>
<?php if($gears == -1 || $addGearAction == -1){ ?>
API ERROR | <?php echo $translationsGearGears['gear_gear_API_error_-1']; ?> (-1).
<?php }else{ ?>
<?php if($gears == -2 || $addGearAction == -2){ ?>
API ERROR | <?php echo $translationsGearGears['gear_gear_API_error_-2']; ?> (-2).
<?php }else{ ?>
<?php if($addGearAction == -3){ ?>
<?php echo $translationsGearGears['gear_gear_error_addGear_-3']; ?> (-3).
<?php } ?>
<?php } ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<!-- Info banners -->
<?php if($gears == NULL || $_GET["invalidGear"] == 1){ ?>
<div class="alert alert-warning alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-triangle-exclamation me-1"></i>
<div>
<?php if($users == NULL){ ?>
<?php echo $translationsGearGears['gear_gear_info_searchGear_NULL']; ?> (NULL).
<?php }else{ ?>
<?php if($_GET["invalidGear"] == 1){ ?>
<?php echo $translationsGearGears['gear_gear_info_fromGear_invalidGear']; ?> (1).
<?php } ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<!-- Success banners -->
<?php if($addGearAction == 0 || $_GET["deleteGear"] == 1){ ?>
<div class="alert alert-success alert-dismissible d-flex align-items-center" role="alert">
<div>
<i class="fa-regular fa-circle-check me-1"></i>
<?php if($addGearAction == 0){ ?>
<?php echo $translationsGearGears['gear_gear_success_gearAdded']; ?>
<?php }else{ ?>
<?php if($_GET["deleteGear"] == 1){ ?>
<?php echo $translationsGearGears['gear_gear_success_gearDeleted']; ?>
<?php } ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<div class="row row-gap-3">
<div class="col-lg-4 col-md-12">
<!-- Add gear zone -->
<p><?php echo $translationsGearGears['gear_gear_buttonLabel_addGear']; ?></p>
<a class="w-100 btn btn-primary" href="#" role="button" data-bs-toggle="modal" data-bs-target="#addGearModal"><?php echo $translationsGearGears['gear_gear_button_addGear']; ?></a>
<!-- Modal add gear -->
<div class="modal fade" id="addGearModal" tabindex="-1" aria-labelledby="addGearModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="addGearModal"><?php echo $translationsGearGears['gear_gear_modal_addGear_title']; ?></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="../gear/gears.php?addGear=1" method="post" enctype="multipart/form-data">
<div class="modal-body">
<!-- brand fields -->
<label for="gearBrandAdd"><b><?php echo $translationsGearGears['gear_gear_modal_addEditGear_brandLabel']; ?></b></label>
<input class="form-control" type="text" name="gearBrandAdd" placeholder="<?php echo $translationsGearGears['gear_gear_modal_addEditGear_brandPlaceholder']; ?>" maxlength="45" value="<?php echo($_POST["gearBrandAdd"]); ?>">
<!-- model fields -->
<label for="gearModelAdd"><b><?php echo $translationsGearGears['gear_gear_modal_addEditGear_modelLabel']; ?></b></label>
<input class="form-control" type="text" name="gearModelAdd" placeholder="<?php echo $translationsGearGears['gear_gear_modal_addEditGear_modelPlaceholder']; ?>" maxlength="45" value="<?php echo($_POST["gearModelAdd"]); ?>">
<!-- nickname fields -->
<label for="gearNicknameAdd"><b><?php echo $translationsGearGears['gear_gear_modal_addEditGear_nicknameLabel']; ?></b></label>
<input class="form-control" type="text" name="gearNicknameAdd" placeholder="<?php echo $translationsGearGears['gear_gear_modal_addEditGear_nicknamePlaceholder']; ?>" maxlength="45" value="<?php echo($_POST["gearNicknameAdd"]); ?>">
<!-- gear type fields -->
<label for="gearTypeAdd"><b>* <?php echo $translationsGearGears['gear_gear_modal_addEditUser_gearTypeLabel']; ?></b></label>
<select class="form-control" name="gearTypeAdd">
<option value="1" <?php if($_POST["gearTypeAdd"] == 1){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGears['gear_gear_modal_addEditUser_gearTypeOption1']; ?></option>
<option value="2" <?php if($_POST["gearTypeAdd"] == 2){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGears['gear_gear_modal_addEditUser_gearTypeOption2']; ?></option>
<option value="3" <?php if($_POST["gearTypeAdd"] == 3){ ?> selected="selected" <?php } ?>><?php echo $translationsGearGears['gear_gear_modal_addEditUser_gearTypeOption3']; ?></option>
</select required>
<!-- date fields -->
<label for="gearDateAdd"><b><?php echo $translationsGearGears['gear_gear_modal_addEditGear_dateLabel']; ?></b></label>
<input class="form-control" type="date" name="gearDateAdd" placeholder="<?php echo $translationsGearGears['gear_gear_modal_addEditGear_datePlaceholder']; ?>" value="<?php echo($_POST["gearDateAdd"]); ?>" required>
* <?php echo $translationsTemplateTop['template_top_global_requiredFields']; ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo $translationsTemplateTop['template_top_global_close']; ?></button>
<button type="submit" class="btn btn-success" name="addGear"><?php echo $translationsGearGears['gear_gear_modal_addGear_title']; ?></button>
</div>
</form>
</div>
</div>
</div>
<br>
<p><?php echo $translationsGearGears['gear_gear_buttonLabel_searchGear']; ?></p>
<form action="../gear/gears.php" method="post">
<div class="mb-3">
<!--<label for="userUsername"><b>Username</b></label>-->
<input class="form-control" type="text" name="gearNickname" placeholder="<?php echo $translationsGearGears['gear_gear_form_searchGear_nicknamePlaceholder']; ?>" required>
</div>
<button class="w-100 btn btn-success" type="submit" name="gearSearch"><?php echo $translationsGearGears['gear_gear_button_searchGear']; ?></button>
</form>
<?php if(isset($_POST["gearSearch"])){ ?>
<br>
<a class="w-100 btn btn-primary" href="../gear/gears.php" role="button"><?php echo $translationsTemplateTop['template_top_global_button_listAll']; ?></a>
<?php } ?>
</div>
<div class="col">
<?php if($gears == -1 || $numGears == -1 || $gears == -2){ ?>
<div class="alert alert-danger alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-exclamation"></i>
<div>
<?php if($gears == -1 || $numGears == -1 || $gears == -2){ ?>
<?php echo $translationsGearGears['gear_gear_error_listGear_-1-2']; ?> (-1/-2).
<?php } ?>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php }else{ ?>
<!-- Info banners -->
<?php if($gears == -3){ ?>
<div class="alert alert-warning alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-triangle-exclamation"></i>
<div>
<?php if($gears == -3){ ?>
<?php echo $translationsGearGears['gear_gear_error_listGear_-3']; ?> (-3).
<?php } ?>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php }else{ ?>
<p><?php echo $translationsGearGears['gear_gear_list_title1']; ?> <?php echo ($numGears); ?> <?php echo $translationsGearGears['gear_gear_list_title2']; ?> (<?php echo $numRecords; ?> <?php echo $translationsGearGears['gear_gear_list_title3']; ?>:</p>
<ul class="list-group list-group-flush">
<?php foreach ($gears as $gear) { ?>
<li class="list-group-item d-flex justify-content-between">
<div class="d-flex align-items-center">
<img src=<?php if($gear["gear_type"] == 1){ echo ("../img/avatar/bicycle1.png"); }else{ if($gear["gear_type"] == 2){ echo ("../img/avatar/running_shoe1.png"); }else{ echo ("../img/avatar/wetsuit1.png"); }} ?> alt="gearPicture" width="55" height="55">
<!--<img src=<?php if($gear["gear_type"] == 1){ echo ("../img/avatar/bicycle1.png"); }else{ if($gear["gear_type"] == 2){ echo ("../img/avatar/running_shoe1.png"); }else{ echo ("../img/avatar/wetsuit1.png"); }} ?> alt="gearPicture" class="rounded-circle" width="55" height="55">-->
<div class="ms-3">
<div class="fw-bold">
<!--<?php echo ($gear["nickname"]); ?>-->
<a href="../gear/gear.php?gearID=<?php echo ($gear["id"]); ?>" class="link-underline-opacity-25 link-underline-opacity-100-hover"><?php echo ($gear["nickname"]); ?></a>
</div>
<b><?php echo $translationsGearGears['gear_gear_gear_type']; ?></b><?php if($gear["gear_type"] == 1){ echo $translationsGearGears['gear_gear_modal_addEditUser_gearTypeOption1']; }else{ if($gear["gear_type"] == 2){ echo $translationsGearGears['gear_gear_modal_addEditUser_gearTypeOption2']; }else{ if($gear["gear_type"] == 3){ echo $translationsGearGears['gear_gear_modal_addEditUser_gearTypeOption3']; }}} ?>
</br>
</div>
</div>
<div>
<?php if($gear["is_active"] == 1){ ?>
<span class="badge bg-success-subtle border border-success-subtle text-success-emphasis align-middle"><?php echo $translationsGearGears['gear_gear_list_isactive']; ?></span>
<?php }else{ ?>
<span class="badge bg-danger-subtle border border-danger-subtle text-danger-emphasis align-middle"><?php echo $translationsGearGears['gear_gear_list_isinactive']; ?></span>
<?php } ?>
</div>
<!--<a class="btn btn-link btn-rounded btn-lg" href="../gear/gear.php?gearID=<?php echo ($gear["id"]); ?>" role="button">View</a>
<a class="btn btn-link btn-lg" href="../gear/gear.php?gearID=<?php echo ($gear["id"]); ?>" role="button" ><i class="fa-solid fa-arrow-up-right-from-square"></i></a>-->
</li>
<?php } ?>
</ul>
<?php if(!isset($_POST["gearSearch"])){ ?>
<br>
<nav>
<ul class="pagination justify-content-center">
<li class="page-item <?php if($pageNumber == 1){ echo "disabled"; } ?>"><a class="page-link" href="?pageNumber=1">«</a></li>
<?php for ($i = 1; $i <= $total_pages; $i++) { ?>
<li class="page-item <?php if($i == $pageNumber){ echo "active"; } ?>"><a class="page-link" href="?pageNumber=<?php echo ($i);?>"><?php echo ($i);?></a></li>
<?php } ?>
<li class="page-item <?php if($pageNumber == $total_pages){ echo "disabled"; } ?>"><a class="page-link" href="?pageNumber=<?php echo ($total_pages);?>">»</a></li>
</ul>
</nav>
<?php } ?>
<?php } ?>
<?php } ?>
</div>
</div>
<div>
<br>
<button onclick="window.history.back();" type="button" class="w-100 btn btn-primary d-lg-none"><?php echo $translationsTemplateTop['template_top_global_back']; ?></button>
</div>
</div>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Bottom.php" ?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
frontend/img/logo/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@@ -0,0 +1,10 @@
<!-- Footer -->
<footer class="border-top py-3 my-4 bg-body-tertiar">
<p class="text-center text-muted">&copy; <?php if(date("Y") == 2023) {
echo date("Y");
}else{ ?>2023-<?php echo date("Y");
}?> Gear Guardian | <a href="https://github.com/joaovitoriasilva/gearguardian" role="button">Frontend <i class="fa-brands fa-github"></i></a> | <a href="https://github.com/joaovitoriasilva/gearguardian-backend" role="button">Backend <i class="fa-brands fa-github"></i></a>
</p>
<p class="text-center text-muted"><img src="../img/strava/api_logo_cptblWith_strava_horiz_light.png" alt="Compatible with STRAVA image" height="25"/></p>
</body>
</html>

91
frontend/inc/Template-Top.php Executable file
View File

@@ -0,0 +1,91 @@
<?php
// Load the language file based on the user's preferred language
switch ($_SESSION["preferred_language"]) {
case 'en':
$translationsTemplateTop = include $_SERVER['DOCUMENT_ROOT'].'/lang/inc/Template-Top/en.php';
break;
case 'pt':
$translationsTemplateTop = include $_SERVER['DOCUMENT_ROOT'].'/lang/inc/Template-Top/pt.php';
break;
// ...
default:
$translationsTemplateTop = include $_SERVER['DOCUMENT_ROOT'].'/lang/inc/Template-Top/en.php';
}
?>
<!DOCTYPE html>
<html data-bs-theme="default" lang="pt">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Gear Guardian</title>
<!--<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>-->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.2.0/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>-->
<script src="https://kit.fontawesome.com/8c44ee63d9.js"></script>
<link rel="shortcut icon" href="../img/logo/logo.png">
<link rel="apple-touch-icon" href="../img/logo/logo.png">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<script>
// Used to toggle the menu on small screens when clicking on the menu button
function showNav() {
var x = document.getElementById("navSmallScreens");
if (x.className.indexOf("w3-show") == -1) {
x.className += " w3-show";
} else {
x.className = x.className.replace(" w3-show", "");
}
}
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const html = document.querySelector('html');
if (prefersDark) {
html.setAttribute('data-bs-theme', 'dark');
} else {
html.setAttribute('data-bs-theme', 'default');
}
</script>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<!--<img src="../img/logo/logo.png" alt="Logo" width="24" height="24" class="rounded-circle d-inline-block align-text-top m-2">-->
<img src="../img/logo/logo.png" alt="Logo" width="30" class="d-inline-block align-text-top m-2">
<a class="navbar-brand" href="../index.php">Gear Guardian</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav me-auto mb-2 mb-lg-0">
<?php if(isLogged()) {?>
<a class="nav-link <?php if(str_contains($page, "gear")){ echo ("active"); }?>" href="../gear/gears.php"><i class="fa-solid fa-bicycle"></i> <?php echo $translationsTemplateTop['template_top_navbar_gear']; ?></a>
<?php } ?>
</div>
<div class="navbar-nav d-flex">
<?php if(isLogged()) {?>
<span class="border-top d-sm-none d-block mb-2"></span>
<a class="nav-link" href="../settings/settings.php?profileSettings=1">
<img src="<?php if(is_null($_SESSION["photo_path"])){ if($_SESSION["gender"] == 1) { echo ("../img/avatar/farmer_avatar_male_1.png"); }else{ echo ("../img/avatar/farmer_avatar_female_1.png"); } }else{ echo ($_SESSION["photo_path"]); }?>" alt="userPhoto" width="24" height="24" class="rounded-circle"><span class="ms-2"><?php echo $translationsTemplateTop['template_top_navbar_profile']; ?></span>
</a>
<span class="border-top d-sm-none d-block mb-2"></span>
<a class="nav-link d-none d-sm-block">|</a>
<a class="nav-link" href="../settings/settings.php"><i class="fa-solid fa-gear"></i> <?php echo $translationsTemplateTop['template_top_navbar_settings']; ?></a>
<a class="nav-link" href="../logout.php"><i class="fas fa-sign-out-alt"></i> <?php echo $translationsTemplateTop['template_top_navbar_logout']; ?></a>
<?php }else{ ?>
<a class="nav-link" href="../login.php"><i class="fas fa-sign-in-alt"></i> <?php echo $translationsTemplateTop['template_top_navbar_login']; ?></a>
<?php } ?>
</div>
</div>
</div>
</nav>
<div class="alert alert-warning alert-dismissible d-flex align-items-center mx-2 my-2 justify-content-center" role="alert">
<i class="fa-solid fa-triangle-exclamation me-1"></i>
<div>
<span><?php echo $translationsTemplateTop['template_top_warning_zone']; ?></span>
</div>
</div>

View File

@@ -0,0 +1,447 @@
<?php
/* ************************************************************************** */
/* Activies */
/* ************************************************************************** */
/* Get all activities */
function getActivities(){
$response = callAPIRoute("/activities/all", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get user activities */
function getUserActivities(){
$response = callAPIRoute("/activities/useractivities", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get user activities */
function getUserActivitiesThisWeekDistances($userID){
$response = callAPIRoute("/activities/useractivities/$userID/thisweek/distances", 0, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get all gear activities */
function getGearActivities($gearID){
$response = callAPIRoute("/activities/gear/$gearID", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get all activities with pagination */
function getActivitiesPagination($pageNumber, $numRecords){
$response = callAPIRoute("/activities/all/pagenumber/$pageNumber/numRecords/$numRecords", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get user activities with pagination */
function getUserActivitiesPagination($pageNumber, $numRecords){
$response = callAPIRoute("/activities/useractivities/pagenumber/$pageNumber/numRecords/$numRecords", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get number of activities */
function numActivities(){
$response = callAPIRoute("/activities/all/number", 0, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
$data = json_decode($response[0], true);
return $data[0];
} else {
return -2;
}
}
}
/* Get user number of activities */
function numUserActivities(){
$response = callAPIRoute("/activities/useractivities/number", 0, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
$data = json_decode($response[0], true);
return $data[0];
} else {
return -2;
}
}
}
/* Get gear from id */
function getActivityFromId($id){
$response = callAPIRoute("/activities/$id/activityfromid", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* adds gear_id to activity */
function addGearToActivity($activityID, $gearID){
$response = callAPIRoute("/activities/$activityID/addgear/$gearID", 0, 3, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
/* Creates a new activity */
function newActivity($distance, $name, $type, $starttime, $endtime, $town, $country, $city, $waypoints, $elevationGain, $elevationLoss, $pace, $averageSpeed, $averagePower, $strava_id){
$response = callAPIRoute("/activities/create", 0, 4, json_encode(array(
'distance' => $distance,
'name' => $name,
'type' => $type,
'starttime' => $starttime,
'endtime' => $endtime,
'city' => $city,
'town' => $town,
'country' => $country,
'waypoints' => $waypoints,
'elevationGain' => $elevationGain,
'elevationLoss' => $elevationLoss,
'pace' => $pace,
'averageSpeed' => $averageSpeed,
'averagePower' => $averagePower,
'strava_id' => $strava_id,
)));
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
// $data = json_decode($response[0], true);
// if (isset($data['id'])) {
// return $data['id']; // Return the activity ID.
// } else {
// return -2; // Response doesn't contain the ID.
// }
} else {
return -2;
}
}
}
function parseActivityGPX($gpx_file){
try {
$xml = simplexml_load_file($gpx_file);
if ($xml === false) {
throw new Exception("Invalid GPX file or could not load the file.");
}
if ((string)$xml['creator'] != 'StravaGPX' && (string)$xml['creator'] != 'Garmin Connect') {
return -5;
}
// Extract metadata
$activityType = (string)($xml->trk->type ?? "Workout"); // Extract activity type
$activityName = (string)($xml->trk->name ?? "Workout" ); // Extract activity name
$distance = 0; // Initialize total distance to 0
$firstWaypointTime = null; // Variable to store the first waypoint time
$lastWaypointTime = null; // Variable to store the last waypoint time
$city = null; // Variable to store the last waypoint time
$town = null; // Variable to store the last waypoint time
$country = null; // Variable to store the last waypoint time
$processOneTimeFields = 0;
$elevationGain = 0;
$elevationLoss = 0;
$pace = 0;
// Extract the start time from metadata
#$startTime = (string)$xml->metadata->time;
$waypoints = [];
$prevLatitude = null;
$prevLongitude = null;
// Iterate through track segments and track points
foreach ($xml->trk->trkseg->trkpt as $point) {
$latitude = (float)$point['lat'];
$longitude = (float)$point['lon'];
if ($prevLatitude !== null && $prevLongitude !== null) {
// Calculate distance between waypoints (Haversine formula) and add to total distance
$distance += calculateDistance($prevLatitude, $prevLongitude, $latitude, $longitude);
}
$elevation = (float)$point->ele;
// You can access other data like time, heart rate, cadence, etc. from the extensions as needed
$time = (string)$point->time;
// Store the first and last waypoint times
if ($firstWaypointTime === null) {
$firstWaypointTime = $time;
}
// Store the town and country
if($processOneTimeFields == 0){
$url = "https://geocode.maps.co/reverse?lat=$latitude&lon=$longitude";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
try {
$response = curl_exec($ch);
#echo $response;
if ($response !== false) {
// Parse the JSON response
$data = json_decode($response);
#echo $data;
// Extract the town and country from the address components
if(isset($data->address->city)){
$city = (string)$data->address->city;
}
if(isset($data->address->town)){
$town = (string)$data->address->town;
}
if(isset($data->address->country)){
$country = (string)$data->address->country;
}
}
} catch (Exception $e) {
echo "An error occurred: " . $e->getMessage();
}
curl_close($ch);
$processOneTimeFields = 1;
}
if ((string)$xml['creator'] === 'StravaGPX') {
$heartRate = (int)$point->extensions->children('gpxtpx', true)->TrackPointExtension->hr;
$cadence = (int)$point->extensions->children('gpxtpx', true)->TrackPointExtension->cad;
}else{
$heartRate = (int)$point->extensions->children('ns3', true)->TrackPointExtension->hr;
$cadence = (int)$point->extensions->children('ns3', true)->TrackPointExtension->cad;
}
$power = (int)$point->extensions->power;
$instantSpeed = (float)calculateInstantSpeed($lastWaypointTime, $time, $latitude, $longitude, $prevLatitude, $prevLongitude);
if ($instantSpeed > 0) {
$instantPace = 1/$instantSpeed; // Calculate instant pace in s/m
} else {
$instantPace = 0; // Avoid division by zero for points with zero speed
}
$waypoints[] = [
'lat' => $latitude,
'lon' => $longitude,
'ele' => $elevation,
'time' => $time,
'hr' => $heartRate,
'cad' => $cadence,
'power' => $power,
'vel' => $instantSpeed,
'pace' => $instantPace,
];
// Update previous latitude and longitude for the next iteration
$prevLatitude = $latitude;
$prevLongitude = $longitude;
$lastWaypointTime = $time;
}
$elevationData = calculateElevationGainLoss($waypoints);
$elevationGain = $elevationData['elevationGain'];
$elevationLoss = $elevationData['elevationLoss'];
$pace = calculatePace($distance, $firstWaypointTime, $lastWaypointTime);
$averageSpeed = calculateAverageSpeed($distance, $firstWaypointTime, $lastWaypointTime);
$averagePower = calculateAveragePower($waypoints);
return newActivity(intval(number_format($distance, 0, '', '')), $activityName, $activityType, $firstWaypointTime, $lastWaypointTime, $town, $country, $city, $waypoints, $elevationGain, $elevationLoss, number_format($pace,10), number_format($averageSpeed,10), $averagePower, null);
} catch (Exception $e) {
// Handle the exception
#echo "Error: " . $e->getMessage();
// You can log the error, redirect the user, or take appropriate action.
return -4;
}
}
// Function to calculate distance
function calculateDistance($lat1, $lon1, $lat2, $lon2) {
// The radius of the Earth in meters (mean value)
$earthRadius = 6371000; // 6,371 km = 6,371,000 meters
// Convert latitude and longitude from degrees to radians
$lat1 = deg2rad($lat1);
$lon1 = deg2rad($lon1);
$lat2 = deg2rad($lat2);
$lon2 = deg2rad($lon2);
// Haversine formula
$latDiff = $lat2 - $lat1;
$lonDiff = $lon2 - $lon1;
$a = sin($latDiff / 2) * sin($latDiff / 2) + cos($lat1) * cos($lat2) * sin($lonDiff / 2) * sin($lonDiff / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$distance = $earthRadius * $c;
return $distance;
}
// Add this function to calculate elevation gain and loss
function calculateElevationGainLoss($waypoints) {
$elevationGain = 0;
$elevationLoss = 0;
$prevElevation = null;
foreach ($waypoints as $waypoint) {
$elevation = $waypoint['ele'];
if ($prevElevation !== null) {
$elevationChange = $elevation - $prevElevation;
if ($elevationChange > 0) {
$elevationGain += $elevationChange;
} else {
$elevationLoss -= $elevationChange;
}
}
$prevElevation = $elevation;
}
return ['elevationGain' => $elevationGain, 'elevationLoss' => $elevationLoss];
}
// Add this function to calculate pace
function calculatePace($distance, $firstWaypointTime, $lastWaypointTime) {
// Convert the time strings to DateTime objects
$startDateTime = new DateTime($firstWaypointTime);
$endDateTime = new DateTime($lastWaypointTime);
// Calculate the time difference in seconds
$totalTimeInSeconds = $endDateTime->getTimestamp() - $startDateTime->getTimestamp();
// Calculate pace in seconds per meter
$paceInSecondsPerMeter = $totalTimeInSeconds / $distance;
return $paceInSecondsPerMeter;
}
function calculateInstantSpeed($prevTime, $time, $latitude, $longitude, $prevLatitude, $prevLongitude) {
$timeCalc = new DateTime($time);
$prevTimeCalc = new DateTime($prevTime);
if ($prevTimeCalc !== null) {
$timeDifference = $timeCalc->getTimestamp() - $prevTimeCalc->getTimestamp();
if ($timeDifference > 0) {
$distance = calculateDistance($prevLatitude, $prevLongitude, $latitude, $longitude);
$instantSpeed = $distance / $timeDifference;
}
}
return $instantSpeed; // output in m/s
}
function calculateAverageSpeed($distance, $firstWaypointTime, $lastWaypointTime) {
// Convert the time strings to DateTime objects
$startDateTime = new DateTime($firstWaypointTime);
$endDateTime = new DateTime($lastWaypointTime);
// Calculate the time difference in seconds
$totalTimeInSeconds = $endDateTime->getTimestamp() - $startDateTime->getTimestamp();
// Calculate average speed in meters per second
$averageSpeed = $distance / $totalTimeInSeconds;
return $averageSpeed;
}
function calculateAveragePower($waypoints) {
$totalPower = 0;
$numDataPoints = count($waypoints);
foreach ($waypoints as $waypoint) {
$totalPower += $waypoint['power'];
}
if ($numDataPoints > 0) {
$averagePower = $totalPower / $numDataPoints;
return $averagePower;
} else {
return 0; // Avoid division by zero in case of no data points
}
}
/* Unset activity gear */
function unsetActivityGear($id){
$response = callAPIRoute("/activities/$id/deletegear", 0, 3, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
/* Deletes an activity based on its ID */
function deleteActivity($id){
$response = callAPIRoute("/activities/$id/delete", 0, 1, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
?>

View File

@@ -0,0 +1,176 @@
<?php
/* ************************************************************************** */
/* Gear */
/* ************************************************************************** */
/* Get all gear */
function getGear(){
$response = callAPIRoute("/gear/all", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get all gear for running*/
function getGearForRunning(){
$response = callAPIRoute("/gear/all/running", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get all gear for running*/
function getGearForCycling(){
$response = callAPIRoute("/gear/all/cycling", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get all gear for running*/
function getGearForSwimming(){
$response = callAPIRoute("/gear/all/swimming", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get all gear with pagination */
function getGearPagination($pageNumber, $numRecords){
$response = callAPIRoute("/gear/all/pagenumber/$pageNumber/numRecords/$numRecords", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get number of gear */
function numGears(){
$response = callAPIRoute("/gear/number", 0, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
$data = json_decode($response[0], true);
return $data[0];
} else {
return -2;
}
}
}
/* Get gear from nickname */
function getGearFromNickname($nickname){
$response = callAPIRoute("/gear/$nickname/gearfromnickname", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get gear from id */
function getGearFromId($id){
$response = callAPIRoute("/gear/$id/gearfromid", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Creates a new gear */
function newGear($brand, $model, $nickname, $gear_type, $date){
if(getGearFromNickname($nickname) != NULL){
return -3;
}
$response = callAPIRoute("/gear/create", 0, 4, json_encode(array(
'brand' => $brand,
'model' => $model,
'nickname' => $nickname,
'gear_type' => $gear_type,
'date' => $date,
)));
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
/* Edit gear */
function editGear($id, $brand, $model, $nickname, $gear_type, $date, $is_active){
$response = callAPIRoute("/gear/$id/edit", 0, 3, json_encode(array(
'brand' => $brand,
'model' => $model,
'nickname' => $nickname,
'gear_type' => $gear_type,
'date' => $date,
'is_active' => $is_active,
)));
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
/* Deletes a gear based on its ID */
function deleteGear($id){
$response = callAPIRoute("/gear/$id/delete", 0, 1, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
?>

View File

@@ -0,0 +1,82 @@
<?php
/* ************************************************************************** */
/* Main API Funcs */
/* ************************************************************************** */
/* Get to call a API route */
function callAPIRoute($endpoint, $multipleReturns, $callType, $dataFields){
$api_url = 'http://192.168.2.80:98';
$responseArray = [];
// Initialize a new cURL session
$ch = curl_init();
// Set the cURL options to make an HTTP GET request to the API endpoint with an OAuth2 bearer token in the Authorization header
curl_setopt($ch, CURLOPT_URL, $api_url . $endpoint);
// 0 GET, 1 DELETE, 2 POST, 3 PUT
if($callType == 1){
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
}else{
if($callType == 2){
curl_setopt($ch, CURLOPT_POST, true);
if($dataFields != NULL){
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($dataFields));
}
}else{
if($callType == 3){
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
if($dataFields != NULL){
curl_setopt($ch, CURLOPT_POSTFIELDS, $dataFields);
}
}else{
if($callType == 4 || $callType == 5){
curl_setopt($ch, CURLOPT_POST, true);
if($dataFields != NULL){
// Set the Content-Type header to specify JSON data
#curl_setopt($ch, CURLOPT_HTTPHEADER, array(
# 'Content-Type: application/json'
#));
curl_setopt($ch, CURLOPT_POSTFIELDS, $dataFields);
}
}
}
}
}
if($multipleReturns == 1){
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Authorization: Bearer {$_SESSION["token"]}"
));
}else{
if($callType == 4 || $callType == 3){
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Content-Type: application/json",
"Authorization: Bearer {$_SESSION["token"]}"
));
}else{
if($callType == 5){
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Content-Type: application/json"
));
}else{
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer {$_SESSION["token"]}"
]);
}
}
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Execute the cURL request and store the response in a variable
$response = curl_exec($ch);
$responseArray[] = $response;
$responseArray[] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
#echo $responseArray[0]." + ".$responseArray[1];
curl_close($ch);
return $responseArray;
}
?>

View File

@@ -0,0 +1,111 @@
<?php
/* ************************************************************************** */
/* Session info */
/* ************************************************************************** */
/* Check if a user is logged */
function isLogged(){
if (isset($_SESSION["id"])){
if ($_SESSION["id"]>=0){
return TRUE;
}
}
return FALSE;
}
/* Check if user token is valid */
function isTokenValid($token){
$response = callAPIRoute("/validate_token", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
$data = json_decode($response[0], true);
if (isset($data["message"]) && $data["message"] === "Token is valid") {
return true;
} else {
return false;
}
} else {
return false;
}
}
}
/* Do a login */
function loginUser($username, $password, $neverExpires){
#$api_url = 'http://192.168.2.80:98';
#$ch = curl_init();
#curl_setopt($ch, CURLOPT_URL, $api_url . '/token');
#curl_setopt($ch, CURLOPT_POST, 1);
#curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
# 'username' => $username,
# 'password' => $password,
# 'loginNeverExpires' => $neverExpires,
#]));
#curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
#$response = curl_exec($ch);
#curl_close($ch);
$response = callAPIRoute("/token", 0, 5, json_encode(array(
'username' => $username,
'password' => $password,
'neverExpires' => $neverExpires,
)));
return $response[0];
}
/* Unset user info */
function clearUserRelatedInfoSession(){
unset($_SESSION["token"]);
unset($_SESSION["id"]);
unset($_SESSION["username"]);
unset($_SESSION["email"]);
unset($_SESSION["name"]);
unset($_SESSION["city"]);
unset($_SESSION["birthdate"]);
unset($_SESSION["preferred_language"]);
unset($_SESSION["gender"]);
unset($_SESSION["access_type"]);
unset($_SESSION["photo_path"]);
unset($_SESSION["photo_path_aux"]);
}
/* Set user info */
function setUserRelatedInfoSession($token){
clearUserRelatedInfoSession();
$_SESSION["token"] = $token;
$response = callAPIRoute("/users/me", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
$user = json_decode($response[0], true);
if($user['is_active'] == 0){
clearUserRelatedInfoSession();
return -3;
}
// Populate the $_SESSION variable with user information
// $_SESSION["token"] = $token;
$_SESSION["id"] = $user['id'];
$_SESSION["name"] = $user['name'];
$_SESSION["username"] = $user['username'];
$_SESSION["email"] = $user['email'];
$_SESSION["city"] = $user['city'];
#$_SESSION["birthdate"] = date("d/m/Y", strtotime($user['birthdate']));
$_SESSION["birthdate"] = $user['birthdate'];
$_SESSION["preferred_language"] = $user['preferred_language'];
$_SESSION["gender"] = $user['gender'];
$_SESSION["access_type"] = $user['access_type'];
$_SESSION["photo_path"] = $user['photo_path'];
$_SESSION["photo_path_aux"] = $user['photo_path_aux'];
$_SESSION["is_strava_linked"] = $user['is_strava_linked'];
return 0;
} else {
return -2;
}
}
}
?>

View File

@@ -0,0 +1,56 @@
<?php
/* ************************************************************************** */
/* Strava */
/* ************************************************************************** */
/* Generate unique user state for strava link */
function setUniqueUserStateStravaLink($state){
$response = callAPIRoute("/strava/set-user-unique-state/$state", 0, 3, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
function unsetUniqueUserStateStravaLink(){
$response = callAPIRoute("/strava/unset-user-unique-state", 0, 3, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
function linkStrava($state){
// Example PHP code for the authentication link
$client_id = '115321';
$redirect_uri = urlencode('https://api-gearguardian.jvslab.pt/strava/strava-callback');
$scope = 'read,read_all,profile:read_all,activity:read,activity:read_all'; // Set your required scope
$strava_auth_url = "http://www.strava.com/oauth/authorize?client_id={$client_id}&response_type=code&redirect_uri={$redirect_uri}&approval_prompt=force&scope={$scope}&state={$state}";
header("Location: ".$strava_auth_url);
}
function getStravaActivities(){
$response = callAPIRoute("/strava/retrieve/activities", 0, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
?>

View File

@@ -0,0 +1,206 @@
<?php
/* ************************************************************************** */
/* Users */
/* ************************************************************************** */
/* Get all users */
function getUsers(){
$response = callAPIRoute("/users/all", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get all users with pagination */
function getUsersPagination($pageNumber, $numRecords){
$response = callAPIRoute("/users/all/pagenumber/$pageNumber/numRecords/$numRecords", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get number of users */
function numUsers(){
$response = callAPIRoute("/users/number", 0, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
$data = json_decode($response[0], true);
return $data[0];
} else {
return -2;
}
}
}
/* Get user from username */
function getUserFromUsername($usernameUser){
$response = callAPIRoute("/users/$usernameUser/userfromusername", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get user from ID */
function getUserFromId($id){
$response = callAPIRoute("/users/$id/userfromid", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get user from ID */
function getUserIdFromUsername($usernameUser){
$response = callAPIRoute("/users/$id/useridfromusername", 1, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get user photo path from ID */
function getUserPhotoFromID($id){
$response = callAPIRoute("/users/$id/userphotofromid", 0, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Get user photo path aux from ID */
function getUserPhotoAuxFromID($id){
$response = callAPIRoute("/users/$id/userphotoauxfromid", 0, 0, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return json_decode($response[0], true);
} else {
return -2;
}
}
}
/* Creates a new user */
function newUser($name, $username, $email, $password, $gender, $preferred_language, $city, $birthdate, $access_type, $photo_path, $photo_path_aux, $is_active){
if(getUserFromUsername($username) != NULL){
return -3;
}
$response = callAPIRoute("/users/create", 0, 4, json_encode(array(
'name' => $name,
'username' => $username,
'email' => $email,
'password' => hash("sha256",$password),
'preferred_language' => $preferred_language,
'city' => $city,
'birthdate' => $birthdate,
'gender' => $gender,
'access_type' => $access_type,
'photo_path' => $photo_path,
'photo_path_aux' => $photo_path_aux,
'is_active' => $is_active,
)));
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
/* Edit user */
function editUser($name, $username, $email, $id, $preferred_language, $city, $birthdate, $gender, $access_type, $photo_path, $photo_path_aux, $is_active){
$response = callAPIRoute("/users/$id/edit", 0, 3, json_encode(array(
'name' => $name,
'username' => $username,
'email' => $email,
'preferred_language' => $preferred_language,
'city' => $city,
'birthdate' => $birthdate,
'gender' => $gender,
'access_type' => $access_type,
'photo_path' => $photo_path,
'photo_path_aux' => $photo_path_aux,
'is_active' => $is_active,
)));
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
/* Unset user photo */
function unsetUserPhoto($id){
$response = callAPIRoute("/users/$id/delete-photo", 0, 3, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
/* Deletes a user based on its ID */
function deleteUser($id){
$response = callAPIRoute("/users/$id/delete", 0, 1, NULL);
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
if ($response[1] === 409) {
return -409;
} else {
return -2;
}
}
}
}
?>

View File

@@ -0,0 +1,21 @@
<?php
/* ************************************************************************** */
/* Waypoints */
/* ************************************************************************** */
function newWaypoint($activityID, $waypoints){
#$response = callAPIRoute("/waypoints/create/$activityID", 0, 4, array(
# 'waypoints' => json_encode($waypoints),
#));
#echo json_encode($waypoints);
$response = callAPIRoute("/waypoints/create/$activityID", 0, 4, json_encode($waypoints));
if ($response[0] === false) {
return -1;
} else {
if ($response[1] === 200) {
return 0;
} else {
return -2;
}
}
}
?>

View File

@@ -0,0 +1,9 @@
<?php
require_once $_SERVER['DOCUMENT_ROOT']."/inc/func/main-api-funcs.php";
require_once $_SERVER['DOCUMENT_ROOT']."/inc/func/session-funcs.php";
require_once $_SERVER['DOCUMENT_ROOT']."/inc/func/users-funcs.php";
require_once $_SERVER['DOCUMENT_ROOT']."/inc/func/gear-funcs.php";
require_once $_SERVER['DOCUMENT_ROOT']."/inc/func/activities-funcs.php";
require_once $_SERVER['DOCUMENT_ROOT']."/inc/func/waypoints-funcs.php";
require_once $_SERVER['DOCUMENT_ROOT']."/inc/func/strava-funcs.php";
?>

410
frontend/index.php Executable file
View File

@@ -0,0 +1,410 @@
<?php
if(!isset($_SESSION)){
session_start();
}
require_once $_SERVER['DOCUMENT_ROOT']."/inc/sqlFunctions.php";
$page="index";
if(!isLogged()){
header("Location: ../login.php");
}
if(!isTokenValid($_SESSION["token"])){
header("Location: ../logout.php?sessionExpired=1");
}
#header("Location: ../gear/gears.php");
// Load the language file based on the user's preferred language
switch ($_SESSION["preferred_language"]) {
case 'en':
$translationsIndex = include $_SERVER['DOCUMENT_ROOT'].'/lang/index/en.php';
break;
case 'pt':
$translationsIndex = include $_SERVER['DOCUMENT_ROOT'].'/lang/index/pt.php';
break;
// ...
default:
$translationsIndex = include $_SERVER['DOCUMENT_ROOT'].'/lang/index/en.php';
}
// activities
$numActivities = 0;
$activities = [];
$pageNumberActivities = 1;
$addActivityAction = -9000;
$editActivityAction = -9000;
$deleteActivityAction = -9000;
// general
$numRecords = 5;
/* Add action */
if(isset($_POST["addActivity"]) && $_GET["addActivity"] == 1){
$fileExtension = pathinfo($_FILES["activityGpxFileAdd"]["name"], PATHINFO_EXTENSION);
if ($fileExtension == "gpx") {
$addActivityAction = parseActivityGPX($_FILES["activityGpxFileAdd"]["tmp_name"]);
}
}
if(isset($_GET["pageNumberActivities"])){
$pageNumberActivities = $_GET["pageNumberActivities"];
}
if(!isset($_POST["activitySearch"])){
$activities = getUserActivitiesPagination($pageNumberActivities, $numRecords);
$numActivities = numUserActivities();
$total_pages = ceil($numActivities / $numRecords);
}else{
#$activities = getGearFromName(urlencode(trim($_POST["gearNickname"])));
#if($activities == NULL){
# $numActivities=0;
#}else{
# $numActivities=1;
#}
}
$thisWeekDistances = getUserActivitiesThisWeekDistances($_SESSION["id"]);
?>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Top.php" ?>
<div class="container mt-4">
<!--<h1><?php echo $translationsIndex['index_title']; ?></h1>-->
</div>
<!-- Page Container -->
<div class="container mt-4">
<div class="row row-gap-3">
<!-- sidebar zone -->
<div class="col-lg-3 col-md-12">
<div class="d-none d-lg-block mt-3 mb-3 d-flex justify-content-center">
<div class="justify-content-center d-flex">
<img src=<?php if(is_null($_SESSION["photo_path"])){
if($_SESSION["gender"] == 1){
echo ("../img/avatar/male1.png");
}else{
echo ("../img/avatar/female1.png");
}
}else{
echo ($_SESSION["photo_path"]);
}?> alt="userPicture" class="rounded-circle" width="120" height="120">
</div>
<div class="text-center mt-3 mb-3 fw-bold">
<a href="../settings/settings.php?profileSettings=1"><?php echo $_SESSION["name"]; ?></a>
</div>
<!-- this week distances zone -->
<span class="fw-lighter"><?php echo $translationsIndex['index_userZone_thisWeekDistances_title']; ?></span>
<div class="row">
<div class="col">
<span class="fw-lighter"><?php echo $translationsIndex['index_userZone_thisWeekDistances_run']; ?></span>
<br>
<?php if($thisWeekDistances["run"] != null){ ?>
<?php echo number_format(($thisWeekDistances["run"] / 1000),2); ?> km
<?php }else{ ?>
0 km
<?php } ?>
</div>
<div class="col border-start border-opacity-50">
<span class="fw-lighter"><?php echo $translationsIndex['index_userZone_thisWeekDistances_bike']; ?></span>
<br>
<?php if($thisWeekDistances["bike"] != null){ ?>
<?php echo number_format(($thisWeekDistances["bike"] / 1000),2); ?> km
<?php }else{ ?>
0 km
<?php } ?>
</div>
<div class="col border-start border-opacity-50">
<span class="fw-lighter"><?php echo $translationsIndex['index_userZone_thisWeekDistances_swim']; ?></span>
<br>
<?php if($thisWeekDistances["swim"] != null){ ?>
<?php if($thisWeekDistances["swim"] > 10000){ ?>
<?php echo number_format(($thisWeekDistances["swim"] / 1000),2); ?> km
<?php }else{ ?>
<?php echo $thisWeekDistances["swim"]; ?> m
<?php } ?>
<?php }else{ ?>
0 m
<?php } ?>
</div>
</div>
</div>
<a class="w-100 btn btn-primary" href="#" role="button" data-bs-toggle="modal" data-bs-target="#addActivityModal"><?php echo $translationsIndex['index_sidebar_addActivity']; ?></a>
<!-- Modal add actvity -->
<div class="modal fade" id="addActivityModal" tabindex="-1" aria-labelledby="addActivityModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="addActivityModal"><?php echo $translationsIndex['index_sidebar_addActivity']; ?></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="../index.php?addActivity=1" method="post" enctype="multipart/form-data">
<div class="modal-body">
<!-- date fields -->
<label for="activityGpxFileAdd"><b>* <?php echo $translationsIndex['index_sidebar_addActivity_modal_addGpxFile_placeholder']; ?></b></label>
<input class="form-control" type="file" name="activityGpxFileAdd" accept=".gpx" placeholder="<?php echo $translationsIndex['index_sidebar_addActivity_modal_addGpxFile_placeholder']; ?>" value="<?php echo($_POST["activityGpxFileAdd"]); ?>" required>
* <?php echo $translationsTemplateTop['template_top_global_requiredFields']; ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo $translationsTemplateTop['template_top_global_close']; ?></button>
<button type="submit" class="btn btn-success" name="addActivity"><?php echo $translationsIndex['index_sidebar_addActivity']; ?></button>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="col">
<!-- Error banners -->
<?php if($activities == -1 || $activities == -2 || $addActivityAction == -1 || $addActivityAction == -2 || $addActivityAction == -3 || $addActivityAction == -4 || $_GET["invalidActivity"] == 1){ ?>
<div class="alert alert-danger alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-exclamation me-1"></i>
<div>
<?php if($activities == -1 || $addActivityAction == -1){ ?>
API ERROR | <?php echo $translationsIndex['index_sidebar_addActivity_API_error_-1']; ?> (-1).
<?php }else{ ?>
<?php if($activities == -2 || $addActivityAction == -2){ ?>
API ERROR | <?php echo $translationsIndex['index_sidebar_addActivity_API_error_-2']; ?> (-2).
<?php }else{ ?>
<?php if($addActivityAction == -3){ ?>
<?php echo $translationsIndex['index_sidebar_addActivity_fileExtensionNotSupported_-3']; ?> (-3).
<?php }else{ ?>
<?php if($addActivityAction == -4){ ?>
<?php echo $translationsIndex['index_sidebar_addActivity_GPXError_-4']; ?> (-4).
<?php }else{ ?>
<?php if($_GET["invalidActivity"] == 1){ ?>
<?php echo $translationsIndex['index_sidebar_invalidActivity']; ?>.
<?php } ?>
<?php } ?>
<?php } ?>
<?php } ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<!-- Info banners -->
<?php if($activities == NULL){ ?>
<div class="alert alert-warning alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-triangle-exclamation me-1"></i>
<div>
<?php if($activities == NULL){ ?>
<?php echo $translationsIndex['index_sidebar_addActivity_info_searchActivity_NULL']; ?> (NULL).
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<!-- Success banners -->
<?php if($addActivityAction == 0 || $_GET["deleteActivity"] == 1){ ?>
<div class="alert alert-success alert-dismissible d-flex align-items-center" role="alert">
<div>
<i class="fa-regular fa-circle-check me-1"></i>
<?php if($addActivityAction == 0){ ?>
<?php echo $translationsIndex['index_sidebar_addActivity_success_activityAdded']; ?>
<?php }else{ ?>
<?php if($_GET["deleteActivity"] == 1){ ?>
<?php echo $translationsIndex['index_sidebar_addActivity_success_activityDeleted']; ?>
<?php } ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<!--<div class="btn-group mb-3 d-flex" role="group" aria-label="Activities radio toggle button group">
<input type="radio" class="btn-check" name="btnradio" id="btnRadioUserActivities" autocomplete="off" checked>
<label class="btn btn-outline-primary w-100" for="btnRadioUserActivities"><?php echo $translationsIndex['activity_radio_userActivities']; ?></label>
<input type="radio" class="btn-check" name="btnradio" id="btnRadioFollowersActivities" autocomplete="off">
<label class="btn btn-outline-primary w-100" for="btnRadioFollowersActivities"><?php echo $translationsIndex['activity_radio_followersActivities']; ?></label>
</div>-->
<div id="userActivitiesDiv" style="display: block;">
<!-- user activities list -->
<?php foreach($activities as $activity){ ?>
<div class="card">
<div class="card-body">
<div class="d-flex align-items-center">
<img src=<?php if(is_null($_SESSION["photo_path"])){
if($_SESSION["gender"] == 1){
echo ("../img/avatar/male1.png");
}else{
echo ("../img/avatar/female1.png");
}
}else{
echo ($_SESSION["photo_path"]);
}?> alt="userPicture" class="rounded-circle" width="55" height="55">
<div class="ms-3 me-3">
<div class="fw-bold">
<a href="activities/activity.php?activityID=<?php echo ($activity["id"]); ?>" class="link-underline-opacity-25 link-underline-opacity-100-hover"><?php echo ($activity["name"]); ?></a>
</div>
<h7><?php if($activity["activity_type"] == 1){
echo '<i class="fa-solid fa-person-running"></i>';
}else{
if($activity["activity_type"] == 4 || $activity["activity_type"] == 5 || $activity["activity_type"] == 6 || $activity["activity_type"] == 8){
echo '<i class="fa-solid fa-person-biking"></i>';
}else{
if($activity["activity_type"] == 7){
echo '<i class="fa-solid fa-person-biking"></i> (Virtual)';
}else{
if($activity["activity_type"] == 9){
echo '<i class="fa-solid fa-person-swimming"></i>';
}else{
if($activity["activity_type"] == 10){
echo '<i class="fa-solid fa-dumbbell"></i>';
}
}
}
}
} ?> <?php echo (new DateTime($activity["start_time"]))->format("d/m/y"); ?>@<?php echo (new DateTime($activity["start_time"]))->format("H:i"); ?><?php if(isset($activity["city"]) || isset($activity["country"])){ echo " - "; }?><?php if(isset($activity["city"]) && !empty($activity["city"])){ echo $activity["city"].", " ; }?><?php if(isset($activity["country"]) && !empty($activity["country"])){ echo $activity["country"]; } ?></h7>
</div>
</div>
<div class="row d-flex mt-3">
<div class="col">
<span class="fw-lighter"><?php echo $translationsIndex['index_activities_detail_distance']; ?></span>
<br>
<?php if($activity["activity_type"] != 9){ ?>
<?php echo number_format(($activity["distance"] / 1000),2); ?> km
<?php }else{ ?>
<?php echo ($activity["distance"]); ?> m
<?php } ?>
</div>
<div class="col border-start border-opacity-50">
<span class="fw-lighter"><?php echo $translationsIndex['index_activities_detail_time']; ?></span>
<br>
<?php
#echo $activity["start_time"];
#echo $activity["end_time"];
$startDateTime = DateTime::createFromFormat("Y-m-d\TH:i:s", $activity["start_time"]);
$endDateTime = DateTime::createFromFormat("Y-m-d\TH:i:s", $activity["end_time"]);
$interval = $startDateTime->diff($endDateTime);
if ($interval->h < 1) {
// If the difference is less than one hour
echo $interval->i . "m " . $interval->s . "s";
} else {
// If the difference is one hour or more
echo $interval->h . "h " . $interval->i . "m";
}
?>
</div>
<div class="col border-start border-opacity-50">
<?php if($activity["activity_type"] != 9 && $activity["activity_type"] != 1){ ?>
<span class="fw-lighter"><?php echo $translationsIndex['index_activities_detail_elevation_gain']; ?></span>
<br>
<?php echo ($activity["elevation_gain"]); ?> m
<?php }else{ ?>
<?php if($activity["activity_type"] == 1 || $activity["activity_type"] == 2 || $activity["activity_type"] == 3){ ?>
<span class="fw-lighter"><?php echo $translationsIndex['index_activities_detail_pace']; ?></span>
<br>
<?php echo floor(($activity["pace"]*1000)/60).":".number_format((((($activity["pace"]*1000)/60) - floor(($activity["pace"]*1000)/60)) * 60),0); ?> min/km
<?php }else{ ?>
<?php if($activity["activity_type"] == 9){ ?>
<span class="fw-lighter"><?php echo $translationsIndex['index_activities_detail_pace']; ?></span>
<br>
<?php echo floor(($activity["pace"]*100)/60).":".number_format((((($activity["pace"]*100)/60) - floor(($activity["pace"]*100)/60)) * 60),0); ?> min/km
<?php } ?>
<?php } ?>
<?php } ?>
</div>
</div>
</div>
<?php if($activity["activity_type"] != 10 && $activity["activity_type"] != 9){ ?>
<div class="ms-3 me-3 <?php if($activity['strava_activity_id'] == null){ echo "mb-3"; } ?>" id="map_<?php echo $activity['id']; ?>" style="height: 300px"></div>
<?php } ?>
<?php if($activity['strava_activity_id'] != null){ ?>
<div class="mb-3">
<span class="fw-lighter ms-3 me-3"><?php echo $translationsIndex['index_activities_stravaText1']; ?><a href="https://www.strava.com/activities/<?php echo $activity['strava_activity_id']; ?>" target="_blank" rel="noopener noreferrer"><?php echo $translationsIndex['index_activities_stravaText2']; ?></a></span>
</div>
<?php } ?>
</div>
<br>
<script>
// JavaScript code to create the map for this activity
var waypoints = <?php echo json_encode($activity['waypoints']); ?>;
var mapId = "map_<?php echo $activity['id']; ?>";
var map = L.map(mapId, {
dragging: false, // Disable panning
touchZoom: false, // Disable touch zoom
scrollWheelZoom: false, // Disable scroll wheel zoom
zoomControl: false // Remove zoom control buttons
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
}).addTo(map);
var latlngs = waypoints.map(function(waypoint) {
return [waypoint.lat, waypoint.lon];
});
L.polyline(latlngs, { color: 'blue' }).addTo(map);
// Calculate the bounds of the polyline and fit the map to those bounds
var bounds = L.latLngBounds(latlngs);
map.fitBounds(bounds);
// Add green dot for the first waypoint
L.marker([waypoints[0].lat, waypoints[0].lon], { icon: L.divIcon({ className: 'bg-success dot' }) }).addTo(map);
// Add red dot for the last waypoint
L.marker([waypoints[waypoints.length - 1].lat, waypoints[waypoints.length - 1].lon], { icon: L.divIcon({ className: 'bg-danger dot' }) }).addTo(map);
</script>
<?php } ?>
<?php if(!isset($_POST["activitySearch"])){ ?>
<br>
<nav>
<ul class="pagination justify-content-center">
<li class="page-item <?php if($pageNumberActivities == 1){ echo "disabled"; } ?>"><a class="page-link" href="?pageNumberActivities=1">«</a></li>
<?php for ($i = 1; $i <= $total_pages; $i++) { ?>
<li class="page-item <?php if($i == $pageNumberActivities){ echo "active"; } ?>"><a class="page-link" href="?pageNumberActivities=<?php echo ($i);?>"><?php echo ($i);?></a></li>
<?php } ?>
<li class="page-item <?php if($pageNumberActivities == $total_pages){ echo "disabled"; } ?>"><a class="page-link" href="?pageNumberActivities=<?php echo ($total_pages);?>">»</a></li>
</ul>
</nav>
<?php } ?>
</div>
<div class="card" id="followersActivitiesDiv" style="display: none;">
</div>
<script>
// Get references to the radio buttons and the div elements
const userActivitiesRadio = document.getElementById('btnRadioUserActivities');
const followersActivitiesRadio = document.getElementById('btnRadioFollowersActivities');
const userActivitiesDiv = document.getElementById('userActivitiesDiv');
const followersActivitiesDiv = document.getElementById('followersActivitiesDiv');
// Add a change event listener to the radio buttons
userActivitiesRadio.addEventListener('change', () => {
userActivitiesDiv.style.display = 'block';
followersActivitiesDiv.style.display = 'none';
});
followersActivitiesRadio.addEventListener('change', () => {
userActivitiesDiv.style.display = 'none';
followersActivitiesDiv.style.display = 'block';
});
</script>
</div>
</div>
<!-- End Page Container -->
</div>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Bottom.php" ?>

View File

@@ -0,0 +1,50 @@
<?php
//activity.php translations
return [
// title zone
"activity_title" => "Activity",
// error banner zone
"activity_addEditGear_API_error_-1" => "Connection to API not possible. Failed to execute cURL request",
"activity_addEditGear_API_error_-2" => "API return code was not 200",
// success banner zone
"activity_success_gearAdded" => "Gear added to activity",
"activity_success_gearEdited" => "Activity gear edited",
"activity_success_gearDeleted" => "Activity gear deleted",
// activity title
"activity_title_dropdown_seeItOnStrava" => "See it on Strava",
"activity_title_dropdown_deleteActivity" => "Delete Activity",
"activity_title_dropdown_deleteActivity_modal_body" => "Are you sure you want to delete activity",
// activity details
"activity_detail_distance" => "Distance",
"activity_detail_time" => "Time",
"activity_detail_elevationGain" => "Elevation gain",
"activity_detail_elevationLoss" => "Elevation loss",
"activity_detail_pace" => "pace",
"activity_detail_avgSpeed" => "Avg speed",
"activity_detail_avgPower" => "Avg power",
// other gear
"activity_gear_title" => "Gear",
"activity_gear_notset" => "Gear not set for this activity",
// add gear
"activity_gear_addGear_title" => "Add gear to activity",
"activity_gear_addGear_label" => "Select gear",
"activity_gear_addGear_submit" => "Add gear",
// edit gear
"activity_gear_editGear_title" => "Edit activity gear",
"activity_gear_editGear_submit" => "Edit gear",
// delete gear zone
"activity_gear_deleteGear_title" => "Delete activity gear",
"activity_gear_deleteGear_body" => "Are you sure you want to delete activity gear",
// data graph
"activity_dataGraph_dataSelection" => "Data selection",
"activity_dataGraph_hr" => "Heart Rate",
"activity_dataGraph_cad" => "Cadence",
"activity_dataGraph_power" => "Power",
"activity_dataGraph_ele" => "Elevation",
"activity_dataGraph_vel" => "Velocity",
"activity_dataGraph_pace" => "Pace",
"activity_dataGraph_title" => "Data graph",
"activity_dataGraph_downsampleDataInfo" => "Downsample data (200 points)"
];
?>

View File

@@ -0,0 +1,46 @@
<?php
//gear.php translations
return [
// error banner zone
"gear_API_error_-1" => "Connection to API not possible. Failed to execute cURL request",
"gear_API_error_-2" => "API return code was not 200",
// success banner zone
"gear_success_gearEdited" => "Gear edited.",
// gear info zone
"gear_gear_infoZone_isactive" => "Active",
"gear_gear_infoZone_isinactive" => "Inactive",
"gear_gear_infoZone_gearisbike" => "Bike",
"gear_gear_infoZone_gearisshoe" => "Shoes",
"gear_gear_infoZone_geariswetsuit" => "Wetsuit",
// edit zone
"gear_gear_infoZone_editbutton" => "Edit gear",
"gear_gear_infoZone_modal_editGear_brandLabel" => "Brand",
"gear_gear_infoZone_modal_editGear_brandPlaceholder" => "Brand (max 45 characters)",
"gear_gear_infoZone_modal_editGear_modelLabel" => "Model",
"gear_gear_infoZone_modal_editGear_modelPlaceholder" => "Model (max 45 characters)",
"gear_gear_infoZone_modal_editGear_nicknameLabel" => "Nickname",
"gear_gear_infoZone_modal_editGear_nicknamePlaceholder" => "Nickname (max 45 characters)",
"gear_gear_infoZone_modal_editGear_gearTypeLabel" => "Gear type",
"gear_gear_infoZone_modal_editGear_gearTypeOption1" => "Bike",
"gear_gear_infoZone_modal_editGear_gearTypeOption2" => "Shoes",
"gear_gear_infoZone_modal_editGear_gearTypeOption3" => "Wetsuit",
"gear_gear_infoZone_modal_editGear_dateLabel" => "Created date",
"gear_gear_infoZone_modal_editGear_datePlaceholder" => "Date",
"gear_gear_infoZone_modal_editGear_gearIsActiveLabel" => "Is active",
"gear_gear_infoZone_modal_editGear_gearIsActiveOption1" => "Yes",
"gear_gear_infoZone_modal_editGear_gearIsActiveOption2" => "No",
// delete zone
"gear_gear_infoZone_modal_deleteGear_body" => "Are you sure you want to delete gear",
"gear_gear_infoZone_deletebutton" => "Delete gear",
// details
"gear_gear_infoZone_distance" => "Distance",
"gear_gear_infoZone_brand" => "Brand",
"gear_gear_infoZone_model" => "Model",
// gear activities
"gear_gear_gearActivities_noactivities" => "Gear is not linked to any activity",
"gear_gear_gearActivities_title" => "Gear activities",
"gear_gear_gearActivities_number" => "(last 10 activities)",
"gear_gear_gearActivities_datelabel" => "Date"
];
?>

View File

@@ -0,0 +1,61 @@
<?php
//gears.php translations
return [
// title zone
"gear_title" => "Gear",
// error banner zone
"gear_gear_API_error_-1" => "Connection to API not possible. Failed to execute cURL request",
"gear_gear_API_error_-2" => "API return code was not 200",
"gear_gear_error_addGear_-3" => "Nickname already exists. Please verify nickname",
"gear_gear_error_editGear_-3" => "Nickname and type field required",
// info banner zone
"gear_gear_info_searchGear_NULL" => "Gear not found",
"gear_gear_info_fromGear_invalidGear" => "Gear not found",
// success banner zone
"gear_gear_success_gearAdded" => "Gear added.",
"gear_gear_success_gearEdited" => "Gear edited.",
"gear_gear_success_gearDeleted" => "Gear deleted.",
// add gear zone
"gear_gear_buttonLabel_addGear" => "Add gear:",
"gear_gear_button_addGear" => "Add gear",
"gear_gear_modal_addGear_title" => "Add gear",
"gear_gear_modal_addEditGear_brandLabel" => "Brand",
"gear_gear_modal_addEditGear_brandPlaceholder" => "Brand (max 45 characters)",
"gear_gear_modal_addEditGear_modelLabel" => "Model",
"gear_gear_modal_addEditGear_modelPlaceholder" => "Model (max 45 characters)",
"gear_gear_modal_addEditGear_nicknameLabel" => "Nickname",
"gear_gear_modal_addEditGear_nicknamePlaceholder" => "Nickname (max 45 characters)",
"gear_gear_modal_addEditUser_gearTypeLabel" => "Gear type",
"gear_gear_modal_addEditUser_gearTypeOption1" => "Bike",
"gear_gear_modal_addEditUser_gearTypeOption2" => "Shoes",
"gear_gear_modal_addEditUser_gearTypeOption3" => "Wetsuit",
"gear_gear_modal_addEditGear_dateLabel" => "Created date",
"gear_gear_modal_addEditGear_datePlaceholder" => "Date",
// search gear zone
"gear_gear_buttonLabel_searchGear" => "Search gear by nickname:",
"gear_gear_button_searchGear" => "Search",
"gear_gear_form_searchGear_nicknamePlaceholder" => "Nickname",
// list gears
// error banner zone
"gear_gear_error_listGear_-1-2" => "It was not possible to list gear",
// info banner zone
"gear_gear_error_listGear_-3" => "Gear does not exist",
// list
"gear_gear_list_title1" => "There is a total of",
"gear_gear_list_title2" => " gear(s)",
"gear_gear_list_title3" => " per page)",
"gear_gear_gear_type" => "Type: ",
"gear_gear_list_isactive" => "Active",
"gear_gear_list_isinactive" => "Inactive",
"gear_gear_list_button_components" => "Gear components",
// edit gear zone
"gear_gear_modal_editGear_title" => "Edit gear",
"gear_gear_modal_editUser_gearIsActiveLabel" => "Is active",
"gear_gear_modal_editUser_gearIsActiveOption1" => "Yes",
"gear_gear_modal_editUser_gearIsActiveOption2" => "No",
// delete gear zone
"gear_gear_modal_deleteGear_title" => "Delete gear",
"gear_gear_modal_deleteGear_body" => "Are you sure you want to delete gear"
];
?>

View File

@@ -0,0 +1,17 @@
<?php
//Template-Top.php translations
return [
"template_top_navbar_gear" => "Gear",
"template_top_navbar_login" => "Login",
"template_top_navbar_profile" => "Profile",
"template_top_navbar_settings" => "Settings",
"template_top_navbar_logout" => "Logout",
// back section
"template_top_global_back" => "Back",
"template_top_global_requiredFields" => "Required field(s)",
"template_top_global_close" => "Close",
"template_top_global_button_listAll" => "List all",
"template_top_warning_zone" => "Alpha software, some features might not work has expected"
];
?>

View File

@@ -0,0 +1,37 @@
<?php
//index.php translations
return [
// title zone
"index_title" => "Feed",
"index_userZone_thisWeekDistances_title" => "This week distances",
"index_userZone_thisWeekDistances_run" => "Run",
"index_userZone_thisWeekDistances_bike" => "Bike",
"index_userZone_thisWeekDistances_swim" => "Swim",
// add activity
"index_sidebar_addActivity" => "Add Activity",
"index_sidebar_addActivity_modal_addGpxFile_placeholder" => "Add GPX activity",
// error banner zone
"index_sidebar_addActivity_API_error_-1" => "Connection to API not possible. Failed to execute cURL request",
"index_sidebar_addActivity_API_error_-2" => "API return code was not 200",
"index_sidebar_addActivity_GPXError_-3" => "Invalid GPX file or could not load the file",
"index_sidebar_addActivity_GPXError_-4" => "Invalid GPX file or could not load the file",
"index_sidebar_invalidActivity" => "Invalid activity. Activity ID not valid or you might not have access to see it",
// info banner zone
"index_sidebar_addActivity_info_searchActivity_NULL" => "Activities not found",
// success banner zone
"index_sidebar_addActivity_success_activityAdded" => "Activity added.",
"index_sidebar_addActivity_success_activityDeleted" => "Activity deleted.",
// radio zone
"activity_radio_userActivities" => "My activities",
"activity_radio_followersActivities" => "Followers activities",
// activities zone
"index_activities_type_title" => "Activity added.",
"index_activities_detail_distance" => "Distance",
"index_activities_detail_time" => "Time",
"index_activities_detail_elevation_gain" => "Elevation gain",
"index_activities_detail_pace" => "Pace",
"index_activities_stravaText1" => "Strava activitity, see it ",
"index_activities_stravaText2" => "here"
];
?>

View File

@@ -0,0 +1,15 @@
<?php
//login.php translations
return [
"login_info_session expired" => "User session expired",
"login_error" => "Unable to login. Check username and password",
"login_API_error_-1" => "Connection to API not possible. Failed to execute cURL request",
"login_API_error_-2" => "API return code was not 200",
"login_API_error_-3" => "User state is inactive. Unable to login",
"login_insert_username" => "Insert username",
"login_password" => "Password",
"login_neverExpires" => "Remember login",
"login_login" => "Login"
// Add more translations here
];
?>

View File

@@ -0,0 +1,243 @@
<?php
//settings.php translations
return [
// title zone
"settings_title" => "Settings",
"settings_sidebar_spaces" => "Spaces",
"settings_sidebar_rooms" => "Rooms",
"settings_sidebar_users" => "Users",
"settings_sidebar_global" => "Global settings",
"settings_sidebar_profileSettings" => "Profile settings",
"settings_sidebar_gearSettings" => "Gear",
// error banner zone
"settings_API_error_-1" => "Connection to API not possible. Failed to execute cURL request",
"settings_API_error_-2" => "API return code was not 200",
"settings_sidebar_spaces_error_deletespace_-3" => "Cannot delete space due to existing dependencies",
"settings_sidebar_rooms_error_deleteroom_-3" => "Cannot delete room due to existing dependencies",
"settings_sidebar_spaces_error_addSpace_-3" => "Space name already exists. Please verify name",
"settings_sidebar_rooms_error_addRoom_-3" => "Room name already exists. Please verify name",
"settings_sidebar_spaces_error_editSpace_-3" => "Name is mandatory",
"settings_sidebar_spaces_error_addEditSpace_-4" => "Photo path invalid",
"settings_sidebar_spaces_error_addEditSpace_-5" => "Only photos with extension .jpg, .jpeg e .png are allowed",
"settings_sidebar_spaces_error_addEditSpace_-6" => "It was not possible to upload photo",
"settings_sidebar_spaces_error_deleteSpacePhoto_-3" => "It was not possible to delete space photo on filesystem. Database not updated",
"settings_sidebar_rooms_error_deleteRoomPhoto_-3" => "It was not possible to delete room photo on filesystem. Database not updated",
"settings_sidebar_profile_error_deleteProfilePhoto_-3" => "It was not possible to delete profile photo on filesystem. Database not updated",
"settings_sidebar_users_error_addUser_-3" => "Username already exists. Please verify username",
"settings_sidebar_users_error_addEditUser_-4" => "Photo path invalid",
"settings_sidebar_users_error_addEditUser_-5" => "Only photos with extension .jpg, .jpeg e .png are allowed",
"settings_sidebar_users_error_addEditUser_-6" => "It was not possible to upload photo",
"settings_sidebar_users_error_editUser_-3" => "Username and type field required",
"settings_sidebar_users_error_deleteUser_-3" => "User cannot delete himself",
"settings_sidebar_users_error_deleteUser_-409" => "User has dependencies. It is not possible to delete",
"settings_sidebar_users_error_deleteUserPhoto_-3" => "It was not possible to delete user photo on filesystem. Database not updated",
// info banner zone
"settings_sidebar_spaces_info_searchSpace_NULL" => "Space not found",
"settings_sidebar_spaces_info_spaces_NULL" => "There is no spaces inserted",
"settings_sidebar_spaces_info_listSpace_-3" => "Space does not exist",
"settings_sidebar_spaces_info_spaceDeleted_photoNotDeleted" => "Space deleted. It was not possible to delete space photo from filesystem.",
"settings_sidebar_rooms_info_searchRoom_NULL" => "Room not found",
"settings_sidebar_rooms_info_rooms_NULL" => "There is no rooms inserted",
"settings_sidebar_rooms_info_listRoom_-3" => "Room does not exist",
"settings_sidebar_rooms_info_roomDeleted_photoNotDeleted" => "Room deleted. It was not possible to delete room photo from filesystem.",
"settings_sidebar_users_info_userDeleted_photoNotDeleted" => "User deleted. It was not possible to delete user photo from filesystem.",
"settings_sidebar_users_error_searchUser_NULL" => "User not found",
// success banner zone
"settings_sidebar_spaces_success_spaceDeleted" => "Space deleted.",
"settings_sidebar_spaces_success_spaceAdded" => "Space added.",
"settings_sidebar_spaces_success_spaceEdited" => "Space edited.",
"settings_sidebar_spaces_success_spacePhotoDeleted" => "Space photo deleted.",
"settings_sidebar_rooms_success_roomDeleted" => "Room deleted.",
"settings_sidebar_rooms_success_roomAdded" => "Room added.",
"settings_sidebar_rooms_success_roomEdited" => "Room edited.",
"settings_sidebar_rooms_success_roomPhotoDeleted" => "Room photo deleted.",
"settings_sidebar_profile_success_profilePhotoDeleted" => "Profile photo deleted.",
"settings_sidebar_profile_success_profileEdited" => "Profile edited",
"settings_sidebar_profile_success_stravaLinked" => "Strava linked with success",
"settings_sidebar_users_success_userAdded" => "User added.",
"settings_sidebar_users_success_userEdited" => "User edited.",
"settings_sidebar_users_success_userDeleted" => "User deleted.",
"settings_sidebar_users_success_userPhotoDeleted" => "User photo deleted.",
// spaces zone
"settings_sidebar_spaces_new" => "New space",
"settings_sidebar_spaces_search" => "Search",
"settings_sidebar_spaces_modal_addSpace_title" => "Add space",
"settings_sidebar_spaces_modal_addEditSpace_photoLabel" => "Space photo",
"settings_sidebar_spaces_modal_addEditSpace_nameLabel" => "Name",
"settings_sidebar_spaces_modal_addEditSpace_namePlaceholder" => "Name (max 45 characters)",
"settings_sidebar_spaces_modal_addEditSpace_cityLabel" => "Town/city",
"settings_sidebar_spaces_modal_addEditSpace_cityPlaceholder" => "Town/city (max 45 characters)",
"settings_sidebar_spaces_modal_addEditSpace_addressLabel" => "Address",
"settings_sidebar_spaces_modal_addEditSpace_addressPlaceholder" => "Address (max 45 characters)",
// spaces list
"settings_sidebar_spaces_list_title1" => "There is a total of",
"settings_sidebar_spaces_list_title2" => " space(s)",
"settings_sidebar_spaces_list_title3" => " per page)",
"settings_sidebar_spaces_list_numberofrooms" => "Number of rooms: ",
// add space zone
"settings_sidebar_button_addSpace" => "Add space",
// edit space zone
"settings_sidebar_button_editSpace_title" => "Edit space",
// delete space/room photo zone
"settings_sidebar_modal_editSpaceRoom_deleteSpaceRoomPhoto" => "Delete photo",
// search space/room zone
"settings_sidebar_form_searchSpaceRoomUser_namePlaceholder" => "Search",
"settings_sidebar_form_searchSpace_namePlaceholder" => "Name",
// delete space modal zone
"settings_sidebar_modal_deleteSpace_title" => "Delete space",
"settings_sidebar_modal_deleteSpace_body" => "Are you sure you want to delete space",
// room zone
"settings_sidebar_rooms_new" => "New room",
// add room zone
"settings_sidebar_button_addRoom" => "Add room",
// edit room zone
"settings_sidebar_button_editRoom_title" => "Edit room",
// rooms zone
"settings_sidebar_rooms_new" => "New room",
"settings_sidebar_rooms_modal_addRoom_title" => "Add room",
"settings_sidebar_rooms_modal_addEditRoom_photoLabel" => "Room photo",
"settings_sidebar_rooms_modal_addEditRoom_nameLabel" => "Name",
"settings_sidebar_rooms_modal_addEditRoom_namePlaceholder" => "Name (max 45 characters)",
"settings_sidebar_rooms_modal_addEditRoom_spaceLabel" => "Space which room belongs",
// room list
"settings_sidebar_rooms_list_title1" => "There is a total of",
"settings_sidebar_rooms_list_title2" => " room(s)",
"settings_sidebar_rooms_list_title3" => " per page)",
"settings_sidebar_rooms_list_spaceName" => "Space: ",
// delete room modal zone
"settings_sidebar_modal_deleteRoom_title" => "Delete room",
"settings_sidebar_modal_deleteRoom_body" => "Are you sure you want to delete room",
// users zone
"settings_sidebar_users_new" => "New user",
"settings_sidebar_users_search" => "Search",
// add room zone
"settings_sidebar_button_addUser" => "Add user",
// add user modal
"settings_sidebar_users_modal_addUser_title" => "Add user",
"settings_sidebar_users_modal_addEditUser_photoLabel" => "User photo",
"settings_sidebar_users_modal_addEditUser_usernameLabel" => "Username",
"settings_sidebar_users_modal_addEditUser_usernamePlaceholder" => "Username (max 45 characters)",
"settings_sidebar_users_modal_addEditUser_emailLabel" => "Email",
"settings_sidebar_users_modal_addEditUser_emailPlaceholder" => "Email (max 45 characters)",
"settings_sidebar_users_modal_addEditUser_nameLabel" => "Name",
"settings_sidebar_users_modal_addEditUser_namePlaceholder" => "Name (max 45 characters)",
"settings_sidebar_users_modal_addEditUser_passwordLabel" => "Password",
"settings_sidebar_users_modal_addEditUser_passwordPlaceholder" => "Password",
"settings_sidebar_users_modal_addEditUser_cityLabel" => "Town/city",
"settings_sidebar_users_modal_addEditUser_cityPlaceholder" => "Town/city (max 45 characters)",
"settings_sidebar_users_modal_addEditUser_birthdateLabel" => "Birth date",
"settings_sidebar_users_modal_addEditUser_genderLabel" => "User gender",
"settings_sidebar_users_modal_addEditUser_genderOption1" => "Male",
"settings_sidebar_users_modal_addEditUser_genderOption2" => "Female",
"settings_sidebar_users_modal_addEditUser_preferredLanguageLabel" => "User prefered language",
"settings_sidebar_users_modal_addEditUser_preferredLanguageOption1" => "English",
"settings_sidebar_users_modal_addEditUser_preferredLanguageOption2" => "Portuguese",
"settings_sidebar_users_modal_addEditUser_typeLabel" => "User type",
"settings_sidebar_users_modal_addEditUser_typeOption1" => "Regular user",
"settings_sidebar_users_modal_addEditUser_typeOption2" => "Administrator",
"settings_sidebar_users_modal_addEditUser_notesLabel" => "Notes",
"settings_sidebar_users_modal_addEditUser_notesPlaceholder" => "Notes (max 250 characters)",
"settings_sidebar_users_modal_addEditUser_isActiveLabel" => "Is active",
"settings_sidebar_users_modal_addEditUser_isActiveOption1" => "Yes",
"settings_sidebar_users_modal_addEditUser_isActiveOption2" => "No",
// search space/room zone
"settings_sidebar_form_searchUser_usernamePlaceholder" => "Username",
// users list
"settings_sidebar_users_list_title1" => "There is a total of",
"settings_sidebar_users_list_title2" => " user(s)",
"settings_sidebar_users_list_title3" => " per page)",
"settings_sidebar_users_list_user_accesstype" => "Access type: ",
"settings_sidebar_users_list_isactive" => "Active",
"settings_sidebar_users_list_isinactive" => "Inactive",
// edit user zone
"settings_sidebar_users_modal_editUser_title" => "Edit user",
// delete user photo zone
"settings_sidebar_users_modal_editUser_deleteUserPhoto" => "Delete photo",
// delete user zone
"settings_sidebar_users_modal_deleteUser_title" => "Delete user",
"settings_sidebar_users_modal_deleteUser_body" => "Are you sure you want to delete user",
// edit profile modal zone
"settings_sidebar_profile_editProfile_title" => "Edit profile",
"settings_sidebar_profile_photo_label" => "Profile photo",
"settings_sidebar_profile_username_label" => "Username",
"settings_sidebar_profile_username_placeholder" => "Username (max 45 characters)",
"settings_sidebar_profile_name_label" => "Name",
"settings_sidebar_profile_name_placeholder" => "Name (max 45 characters)",
"settings_sidebar_profile_email_label" => "Email",
"settings_sidebar_profile_email_placeholder" => "Email (max 45 characters)",
"settings_sidebar_profile_city_label" => "Town/city",
"settings_sidebar_profile_city_placeholder" => "Town/city (max 45 characters)",
"settings_sidebar_profile_birthdate_label" => "Birth date",
"settings_sidebar_profile_gender_label" => "Gender",
"settings_sidebar_profile_gender_option1" => "Male",
"settings_sidebar_profile_gender_option2" => "Female",
"settings_sidebar_profile_preferredLanguage_label" => "Prefered language",
"settings_sidebar_profile_preferredLanguage_option1" => "English",
"settings_sidebar_profile_preferredLanguage_option2" => "Portuguese",
// profile zone
"settings_sidebar_profile_deleteProfilePhoto" => "Delete profile photo",
"settings_sidebar_profile_modal_title_deleteProfilePhoto" => "Delete profile photo",
"settings_sidebar_profile_modal_body_deleteProfilePhoto" => "Are you sure you want to delete the profile photo?",
"settings_sidebar_profile_button_editprofile" => "Edit profile",
"settings_sidebar_profile_gender_male" => "Male",
"settings_sidebar_profile_gender_female" => "Female",
"settings_sidebar_profile_access_type_regular_user" => "Regular user",
"settings_sidebar_profile_access_type_admin" => "Admin",
"settings_sidebar_profile_username_subtitle" => "Username: ",
"settings_sidebar_profile_email_subtitle" => "Email: ",
"settings_sidebar_profile_gender_subtitle" => "Gender: ",
"settings_sidebar_profile_birthdate_subtitle" => "Birthdate: ",
"settings_sidebar_profile_city_subtitle" => "City: ",
"settings_sidebar_profile_access_type_subtitle" => "Access type: ",
"settings_sidebar_profile_preferredlanguage_subtitle" => "Preferred language: ",
// gear zone
// error banner zone
"settings_sidebar_gear_API_error_-1" => "Connection to API not possible. Failed to execute cURL request",
"settings_sidebar_gear_API_error_-2" => "API return code was not 200",
"settings_sidebar_gear_error_addGear_-3" => "Nickname already exists. Please verify nickname",
"settings_sidebar_gear_error_editGear_-3" => "Nickname and type field required",
// info banner zone
"settings_sidebar_gear_info_searchGear_NULL" => "Gear not found",
"settings_sidebar_gear_info_fromGear_invalidGear" => "Gear not found",
// success banner zone
"settings_sidebar_gear_success_gearAdded" => "Gear added.",
"settings_sidebar_gear_success_gearEdited" => "Gear edited.",
"settings_sidebar_gear_success_gearDeleted" => "Gear deleted.",
// add and edit gear zone modal
"settings_sidebar_gear_buttonLabel_addGear" => "Add gear:",
"settings_sidebar_gear_button_addGear" => "Add gear",
"settings_sidebar_gear_modal_addGear_title" => "Add gear",
"settings_sidebar_gear_modal_addEditGear_brandLabel" => "Brand",
"settings_sidebar_gear_modal_addEditGear_brandPlaceholder" => "Brand (max 45 characters)",
"settings_sidebar_gear_modal_addEditGear_modelLabel" => "Model",
"settings_sidebar_gear_modal_addEditGear_modelPlaceholder" => "Model (max 45 characters)",
"settings_sidebar_gear_modal_addEditGear_nicknameLabel" => "Nickname",
"settings_sidebar_gear_modal_addEditGear_nicknamePlaceholder" => "Nickname (max 45 characters)",
"settings_sidebar_gear_modal_addEditGear_gearTypeLabel" => "Gear type",
"settings_sidebar_gear_modal_addEditGear_gearTypeOption1" => "Bike",
"settings_sidebar_gear_modal_addEditGear_gearTypeOption2" => "Shoes",
"settings_sidebar_gear_modal_addEditGear_gearTypeOption3" => "Wetsuit",
"settings_sidebar_gear_modal_addEditGear_dateLabel" => "Created date",
"settings_sidebar_gear_modal_addEditGear_datePlaceholder" => "Date",
// search gear zone
"settings_sidebar_gear_button_searchGear" => "Search",
"settings_sidebar_gear_form_searchGear_nicknamePlaceholder" => "Nickname",
// list
"settings_sidebar_gear_list_title1" => "There is a total of",
"settings_sidebar_gear_list_title2" => " gear(s)",
"settings_sidebar_gear_list_title3" => " per page)",
"settings_sidebar_settings_sidebar_gear_type" => "Type: ",
"settings_sidebar_gear_list_isactive" => "Active",
"settings_sidebar_gear_list_isinactive" => "Inactive",
// edit gear zone
"settings_sidebar_gear_modal_editGear_title" => "Edit gear",
"settings_sidebar_gear_modal_editGear_gearIsActiveLabel" => "Is active",
"settings_sidebar_gear_modal_editGear_gearIsActiveOption1" => "Yes",
"settings_sidebar_gear_modal_editGear_gearIsActiveOption2" => "No",
// delete gear zone
"settings_sidebar_gear_modal_deleteGear_title" => "Delete gear",
"settings_sidebar_gear_modal_deleteGear_body" => "Are you sure you want to delete gear"
];
?>

114
frontend/login.php Executable file
View File

@@ -0,0 +1,114 @@
<?php
if(!isset($_SESSION)){
session_start();
}
require_once $_SERVER['DOCUMENT_ROOT']."/inc/sqlFunctions.php";
$page="login";
if(isLogged()){
header("Location: ../index.php");
}
// Load the language file based on the user's preferred language
/*switch ($_SESSION["preferred_language"]) {
case 'en':
$translationsLogin = include $_SERVER['DOCUMENT_ROOT'].'/lang/login/en.php';
break;
case 'pt':
$translationsLogin = include $_SERVER['DOCUMENT_ROOT'].'/lang/login/pt.php';
break;*/
// ...
//default:
$translationsLogin = include $_SERVER['DOCUMENT_ROOT'].'/lang/login/en.php';
//}
$error = 0;
if(isset($_POST["loginUsername"]) && isset($_POST["loginPassword"])) {
clearUserRelatedInfoSession();
$hashPassword = hash("sha256",$_POST["loginPassword"]);
$neverExpires = false;
if (isset($_POST["loginNeverExpires"]) && $_POST["loginNeverExpires"] === "on") {
$neverExpires = true;
}
$result = loginUser($_POST["loginUsername"], $hashPassword, $neverExpires);
$response = json_decode($result, true);
if (isset($response['access_token'])) {
$error = setUserRelatedInfoSession($response['access_token']);
if ($error == 0){
header("Location: ../index.php");
die();
}
} else {
$error = 1;
}
}
#$random_number = mt_rand(1, 2);
?>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Top.php" ?>
<main class="form-signin w-100 m-auto text-center p-5" style="max-width: 500px">
<!-- Info banners -->
<?php if($_GET["sessionExpired"] == 1){ ?>
<div class="alert alert-warning alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-triangle-exclamation me-1"></i>
<div>
<?php if($_GET["sessionExpired"] == 1){ ?>
<?php echo $translationsLogin['login_info_session expired']; ?>.
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<?php if($error == 1 || $error == -1 || $error == -3 || $error == -3){ ?>
<div class="alert alert-danger alert-dismissible d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-exclamation me-1"></i>
<div>
<?php if($error == 1){ ?>
<?php echo $translationsLogin['login_error']; ?> (1).
<?php }else{ ?>
<?php if($error == -1){ ?>
<?php echo $translationsLogin['login_API_error_-1']; ?> (-1).
<?php }else{ ?>
<?php if($error == -2){ ?>
<?php echo $translationsLogin['login_API_error_-2']; ?> (-2).
<?php }else{ ?>
<?php if($error == -3){ ?>
<?php echo $translationsLogin['login_API_error_-3']; ?> (-3).
<?php } ?>
<?php } ?>
<?php } ?>
<?php } ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<?php } ?>
<form action="../login.php" method="post">
<!--<img class="mb-4 rounded-circle" src="../img/avatar/<?php if($random_number == 1){ echo ("female1"); }else{ echo ("male1"); } ?>.png" alt="avatar" width="150" height="150">-->
<img class="mb-4" src="../img/logo/logo.png" alt="app logo" width="200" height="200">
<br>
<div class="form-floating">
<input type="text" class="form-control" id="floatingInput" placeholder="<?php echo $translationsLogin['login_insert_username']; ?>" name="loginUsername" required>
<label for="loginUsername"><?php echo $translationsLogin['login_insert_username']; ?></label>
</div>
<br>
<div class="form-floating">
<input type="password" class="form-control" placeholder="<?php echo $translationsLogin['login_password']; ?>" name="loginPassword" required>
<label for="loginPassword"><?php echo $translationsLogin['login_password']; ?></label>
</div>
<br>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="loginNeverExpires">
<label class="form-check-label" for="loginNeverExpires"><?php echo $translationsLogin['login_neverExpires']; ?></label>
</div>
<br>
<button class="w-100 btn btn-lg btn-primary" type="submit"><?php echo $translationsLogin['login_login']; ?></button>
</form>
</main>
<?php require_once $_SERVER['DOCUMENT_ROOT']."/inc/Template-Bottom.php" ?>

24
frontend/logout.php Executable file
View File

@@ -0,0 +1,24 @@
<?php
require_once $_SERVER['DOCUMENT_ROOT']."/inc/sqlFunctions.php";
if(!isset($_SESSION)){
session_start();
}
$response = callAPIRoute("/logout/{$_SESSION["id"]}", 1, 1, NULL);
if ($response[0] === false) {
#return -1;
} else {
if ($response[1] === 200) {
#return json_decode($response[0], true);
} else {
#return -2;
}
}
clearUserRelatedInfoSession();
if(isset($_GET["sessionExpired"])){
header("location: ../login.php?sessionExpired=1");
}else{
header("location: ../login.php");
}
?>

File diff suppressed because it is too large Load Diff