mirror of
https://github.com/joaovitoriasilva/endurain.git
synced 2026-01-10 08:17:59 -05:00
New unified modal for add+edit gear + general fixes
[backend] add search gear by nickname if contains or full match logic [frontend] add search gear by nickname if contains or full match logic [frontend] added new unified modal for add and edit gear [frontend] add gear now uses new unified modal [frontend] fixed issue on adding new user if height was not inputed
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import logging
|
||||
|
||||
from fastapi import HTTPException, status
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from urllib.parse import unquote
|
||||
@@ -14,7 +13,9 @@ import core.logger as core_logger
|
||||
|
||||
def get_gear_user_by_id(gear_id: int, db: Session) -> gears_schema.Gear | None:
|
||||
try:
|
||||
gear = db.query(gears_models.Gear).filter(gears_models.Gear.id == gear_id).first()
|
||||
gear = (
|
||||
db.query(gears_models.Gear).filter(gears_models.Gear.id == gear_id).first()
|
||||
)
|
||||
|
||||
# Check if gear is None and return None if it is
|
||||
if gear is None:
|
||||
@@ -26,7 +27,9 @@ def get_gear_user_by_id(gear_id: int, db: Session) -> gears_schema.Gear | None:
|
||||
return gear
|
||||
except Exception as err:
|
||||
# Log the exception
|
||||
core_logger.print_to_log(f"Error in get_gear_user_by_id: {err}", "error", exc=err)
|
||||
core_logger.print_to_log(
|
||||
f"Error in get_gear_user_by_id: {err}", "error", exc=err
|
||||
)
|
||||
# Raise an HTTPException with a 500 Internal Server Error status code
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
@@ -73,7 +76,11 @@ def get_gear_users_with_pagination(
|
||||
def get_gear_user(user_id: int, db: Session) -> list[gears_schema.Gear] | None:
|
||||
try:
|
||||
# Get the gear by user ID from the database
|
||||
gears = db.query(gears_models.Gear).filter(gears_models.Gear.user_id == user_id).all()
|
||||
gears = (
|
||||
db.query(gears_models.Gear)
|
||||
.filter(gears_models.Gear.user_id == user_id)
|
||||
.all()
|
||||
)
|
||||
|
||||
# Check if gear is None and return None if it is
|
||||
if gears is None:
|
||||
@@ -95,18 +102,18 @@ def get_gear_user(user_id: int, db: Session) -> list[gears_schema.Gear] | None:
|
||||
) from err
|
||||
|
||||
|
||||
def get_gear_user_by_nickname(
|
||||
def get_gear_user_contains_nickname(
|
||||
user_id: int, nickname: str, db: Session
|
||||
) -> list[gears_schema.Gear] | None:
|
||||
try:
|
||||
# Unquote the nickname and change "+" to whitespace
|
||||
parsed_nickname = unquote(nickname).replace("+", " ")
|
||||
parsed_nickname = unquote(nickname).replace("+", " ").lower()
|
||||
|
||||
# Get the gear by user ID and nickname from the database
|
||||
gears = (
|
||||
db.query(gears_models.Gear)
|
||||
.filter(
|
||||
gears_models.Gear.nickname.like(f"%{parsed_nickname}%"),
|
||||
func.lower(gears_models.Gear.nickname).like(f"%{parsed_nickname}%"),
|
||||
gears_models.Gear.user_id == user_id,
|
||||
)
|
||||
.all()
|
||||
@@ -124,7 +131,48 @@ def get_gear_user_by_nickname(
|
||||
return gears
|
||||
except Exception as err:
|
||||
# Log the exception
|
||||
core_logger.print_to_log(f"Error in get_gear_user_by_nickname: {err}", "error", exc=err)
|
||||
core_logger.print_to_log(
|
||||
f"Error in get_gear_user_contains_nickname: {err}", "error", exc=err
|
||||
)
|
||||
|
||||
# Raise an HTTPException with a 500 Internal Server Error status code
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Internal Server Error",
|
||||
) from err
|
||||
|
||||
|
||||
def get_gear_user_by_nickname(
|
||||
user_id: int, nickname: str, db: Session
|
||||
) -> gears_schema.Gear | None:
|
||||
try:
|
||||
# Unquote the nickname and change "+" to whitespace
|
||||
parsed_nickname = unquote(nickname).replace("+", " ").lower()
|
||||
|
||||
# Get the gear by user ID and nickname from the database
|
||||
gear = (
|
||||
db.query(gears_models.Gear)
|
||||
.filter(
|
||||
func.lower(gears_models.Gear.nickname) == parsed_nickname,
|
||||
gears_models.Gear.user_id == user_id,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
# Check if gear is None and return None if it is
|
||||
if gear is None:
|
||||
return None
|
||||
|
||||
# Serialize the gear
|
||||
gear_serialized = gears_utils.serialize_gear(gear)
|
||||
|
||||
# return the gear
|
||||
return gear_serialized
|
||||
except Exception as err:
|
||||
# Log the exception
|
||||
core_logger.print_to_log(
|
||||
f"Error in get_gear_user_by_nickname: {err}", "error", exc=err
|
||||
)
|
||||
|
||||
# Raise an HTTPException with a 500 Internal Server Error status code
|
||||
raise HTTPException(
|
||||
@@ -138,7 +186,10 @@ def get_gear_by_type_and_user(gear_type: int, user_id: int, db: Session):
|
||||
# Get the gear by type from the database
|
||||
gear = (
|
||||
db.query(gears_models.Gear)
|
||||
.filter(gears_models.Gear.gear_type == gear_type, gears_models.Gear.user_id == user_id)
|
||||
.filter(
|
||||
gears_models.Gear.gear_type == gear_type,
|
||||
gears_models.Gear.user_id == user_id,
|
||||
)
|
||||
.order_by(gears_models.Gear.nickname)
|
||||
.all()
|
||||
)
|
||||
@@ -155,7 +206,9 @@ def get_gear_by_type_and_user(gear_type: int, user_id: int, db: Session):
|
||||
return gear
|
||||
except Exception as err:
|
||||
# Log the exception
|
||||
core_logger.print_to_log(f"Error in get_gear_by_type_and_user: {err}", "error", exc=err)
|
||||
core_logger.print_to_log(
|
||||
f"Error in get_gear_by_type_and_user: {err}", "error", exc=err
|
||||
)
|
||||
# Raise an HTTPException with a 500 Internal Server Error status code
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
@@ -224,7 +277,9 @@ def get_gear_by_garminconnect_id_from_user_id(
|
||||
except Exception as err:
|
||||
# Log the exception
|
||||
core_logger.print_to_log(
|
||||
f"Error in get_gear_by_garminconnect_id_from_user_id: {err}", "error", exc=err
|
||||
f"Error in get_gear_by_garminconnect_id_from_user_id: {err}",
|
||||
"error",
|
||||
exc=err,
|
||||
)
|
||||
# Raise an HTTPException with a 500 Internal Server Error status code
|
||||
raise HTTPException(
|
||||
@@ -263,7 +318,9 @@ def create_multiple_gears(gears: list[gears_schema.Gear], user_id: int, db: Sess
|
||||
db.rollback()
|
||||
|
||||
# Log the exception
|
||||
core_logger.print_to_log(f"Error in create_multiple_gears: {err}", "error", exc=err)
|
||||
core_logger.print_to_log(
|
||||
f"Error in create_multiple_gears: {err}", "error", exc=err
|
||||
)
|
||||
|
||||
# Raise an HTTPException with a 500 Internal Server Error status code
|
||||
raise HTTPException(
|
||||
@@ -281,8 +338,10 @@ def create_gear(gear: gears_schema.Gear, user_id: int, db: Session):
|
||||
db.commit()
|
||||
db.refresh(new_gear)
|
||||
|
||||
gear_serialized = gears_utils.serialize_gear(new_gear)
|
||||
|
||||
# Return the gear
|
||||
return new_gear
|
||||
return gear_serialized
|
||||
except IntegrityError as integrity_error:
|
||||
# Rollback the transaction
|
||||
db.rollback()
|
||||
@@ -310,7 +369,9 @@ def create_gear(gear: gears_schema.Gear, user_id: int, db: Session):
|
||||
def edit_gear(gear_id: int, gear: gears_schema.Gear, db: Session):
|
||||
try:
|
||||
# Get the gear from the database
|
||||
db_gear = db.query(gears_models.Gear).filter(gears_models.Gear.id == gear_id).first()
|
||||
db_gear = (
|
||||
db.query(gears_models.Gear).filter(gears_models.Gear.id == gear_id).first()
|
||||
)
|
||||
|
||||
# Update the gear
|
||||
if gear.brand is not None:
|
||||
@@ -351,7 +412,9 @@ def edit_gear(gear_id: int, gear: gears_schema.Gear, db: Session):
|
||||
def delete_gear(gear_id: int, db: Session):
|
||||
try:
|
||||
# Delete the gear
|
||||
num_deleted = db.query(gears_models.Gear).filter(gears_models.Gear.id == gear_id).delete()
|
||||
num_deleted = (
|
||||
db.query(gears_models.Gear).filter(gears_models.Gear.id == gear_id).delete()
|
||||
)
|
||||
|
||||
# Check if the gear was found and deleted
|
||||
if num_deleted == 0:
|
||||
@@ -382,7 +445,8 @@ def delete_all_strava_gear_for_user(user_id: int, db: Session):
|
||||
num_deleted = (
|
||||
db.query(gears_models.Gear)
|
||||
.filter(
|
||||
gears_models.Gear.user_id == user_id, gears_models.Gear.strava_gear_id.isnot(None)
|
||||
gears_models.Gear.user_id == user_id,
|
||||
gears_models.Gear.strava_gear_id.isnot(None),
|
||||
)
|
||||
.delete()
|
||||
)
|
||||
|
||||
@@ -85,9 +85,30 @@ async def read_gear_user_number(
|
||||
|
||||
|
||||
@router.get(
|
||||
"/nickname/{nickname}",
|
||||
"/nickname/contains/{nickname}",
|
||||
response_model=list[gears_schema.Gear] | None,
|
||||
)
|
||||
async def read_gear_user_contains_nickname(
|
||||
nickname: str,
|
||||
check_scopes: Annotated[
|
||||
Callable, Security(session_security.check_scopes, scopes=["gears:read"])
|
||||
],
|
||||
token_user_id: Annotated[
|
||||
int, Depends(session_security.get_user_id_from_access_token)
|
||||
],
|
||||
db: Annotated[
|
||||
Session,
|
||||
Depends(core_database.get_db),
|
||||
],
|
||||
):
|
||||
# Return the gears
|
||||
return gears_crud.get_gear_user_contains_nickname(token_user_id, nickname, db)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/nickname/{nickname}",
|
||||
response_model=gears_schema.Gear | None,
|
||||
)
|
||||
async def read_gear_user_by_nickname(
|
||||
nickname: str,
|
||||
check_scopes: Annotated[
|
||||
@@ -129,6 +150,7 @@ async def read_gear_user_by_type(
|
||||
|
||||
@router.post(
|
||||
"/create",
|
||||
response_model=gears_schema.Gear,
|
||||
status_code=201,
|
||||
)
|
||||
async def create_gear(
|
||||
@@ -144,11 +166,8 @@ async def create_gear(
|
||||
Depends(core_database.get_db),
|
||||
],
|
||||
):
|
||||
# Create the gear
|
||||
gear_created = gears_crud.create_gear(gear, token_user_id, db)
|
||||
|
||||
# Return the ID of the gear created
|
||||
return gear_created.id
|
||||
# Create the gear and return it
|
||||
return gears_crud.create_gear(gear, token_user_id, db)
|
||||
|
||||
|
||||
@router.put("/{gear_id}/edit")
|
||||
|
||||
@@ -13,6 +13,8 @@ files:
|
||||
translation: /frontend/app/src/i18n/%two_letters_code%/components/activities/modals/%original_file_name%
|
||||
- source: /frontend/app/src/i18n/us/components/followers/*.json
|
||||
translation: /frontend/app/src/i18n/%two_letters_code%/components/followers/%original_file_name%
|
||||
- source: /frontend/app/src/i18n/us/components/gears/*.json
|
||||
translation: /frontend/app/src/i18n/%two_letters_code%/components/gears/%original_file_name%
|
||||
- source: /frontend/app/src/i18n/us/components/health/*.json
|
||||
translation: /frontend/app/src/i18n/%two_letters_code%/components/health/%original_file_name%
|
||||
- source: /frontend/app/src/i18n/us/components/health/healthWeightZone/*.json
|
||||
|
||||
@@ -92,7 +92,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
searchResults.value = await gears.getGearByNickname(query);
|
||||
searchResults.value = await gears.getGearContainsNickname(query);
|
||||
} catch (error) {
|
||||
push.error(`${t('generalItems.errorFetchingInfo')} - ${error}`)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
<template>
|
||||
<div class="modal fade" :id="action == 'add' ? 'addGearModal' : (action == 'edit' ? editGearModalId : '')" tabindex="-1" :aria-labelledby="action == 'add' ? 'addGearModal' : (action == 'edit' ? editGearModalId : '')" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="addGearModal" v-if="action == 'add'">{{ $t("gearsAddEditUserModalComponent.addEditGearModalAddTitle") }}</h1>
|
||||
<h1 class="modal-title fs-5" :id='editGearModalId' v-else>{{ $t("gearsAddEditUserModalComponent.addEditGearModalEditTitle") }}</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form @submit.prevent="handleSubmit">
|
||||
<div class="modal-body">
|
||||
<!-- brand fields -->
|
||||
<label for="gearBrandAddEdit"><b>{{ $t("gearsAddEditUserModalComponent.addEditGearModalAddBrandLabel") }}</b></label>
|
||||
<input class="form-control" type="text" name="gearBrandAddEdit" :placeholder='$t("gearsAddEditUserModalComponent.addEditGearModalAddBrandLabel")' v-model="newEditGearBrand" maxlength="250">
|
||||
<!-- model fields -->
|
||||
<label for="gearModelAddEdit"><b>{{ $t("gearsAddEditUserModalComponent.addEditGearModalAddModelLabel") }}</b></label>
|
||||
<input class="form-control" type="text" name="gearModelAddEdit" :placeholder='$t("gearsAddEditUserModalComponent.addEditGearModalAddModelLabel")' v-model="newEditGearModel" maxlength="250">
|
||||
<!-- nickname fields -->
|
||||
<label for="gearNicknameAddEdit"><b>* {{ $t("gearsAddEditUserModalComponent.addEditGearModalAddNicknameLabel") }}</b></label>
|
||||
<input class="form-control" :class="{ 'is-invalid': !isNicknameExists }" type="text" name="gearNicknameAddEdit" :placeholder='$t("gearsAddEditUserModalComponent.addEditGearModalAddNicknameLabel")' v-model="newEditGearNickname" maxlength="250" required>
|
||||
<div id="validationNicknameFeedback" class="invalid-feedback" v-if="!isNicknameExists">
|
||||
{{ $t("generalItems.errorNicknameAlreadyExistsFeedback") }}
|
||||
</div>
|
||||
<!-- gear type fields -->
|
||||
<label for="gearTypeAddEdit"><b>* {{ $t("gearsAddEditUserModalComponent.addEditGearModalAddTypeLabel") }}</b></label>
|
||||
<select class="form-control" name="gearTypeAddEdit" v-model="newEditGearType" required>
|
||||
<option value="1">{{ $t("gearsAddEditUserModalComponent.addEditGearModalAddTypeOption1") }}</option>
|
||||
<option value="2">{{ $t("gearsAddEditUserModalComponent.addEditGearModalAddTypeOption2") }}</option>
|
||||
<option value="3">{{ $t("gearsAddEditUserModalComponent.addEditGearModalAddTypeOption3") }}</option>
|
||||
</select>
|
||||
<!-- date fields -->
|
||||
<label for="gearDateAddEdit"><b>* {{ $t("gearsAddEditUserModalComponent.addEditGearModalAddDateLabel") }}</b></label>
|
||||
<input class="form-control" type="date" name="gearDateAddEdit" v-model="newEditGearCreatedDate" required>
|
||||
<!-- gear is_active fields -->
|
||||
<label for="gearIsActiveAddEdit"><b>* {{ $t("gearsAddEditUserModalComponent.addEditGearModalAddIsActiveLabel") }}</b></label>
|
||||
<select class="form-control" name="gearIsActiveAddEdit" v-model="newEditGearIsActive" required>
|
||||
<option value="1">{{ $t("gearsAddEditUserModalComponent.addEditGearModalAddIsActiveOption1") }}</option>
|
||||
<option value="0">{{ $t("gearsAddEditUserModalComponent.addEditGearModalAddIsActiveOption0") }}</option>
|
||||
</select>
|
||||
<!-- initial kilometers fields -->
|
||||
<div v-if="Number(authStore?.user?.units) === 1">
|
||||
<label for="gearInitialKmsAddEdit"><b>* {{ $t("gearsAddEditUserModalComponent.addEditGearModalAddIsInitialKmsLabel") }}</b></label>
|
||||
<input class="form-control" type="number" step="0.1" name="gearInitialKmsAddEdit" v-model="newEditGearInitialKms" required>
|
||||
</div>
|
||||
<!-- initial miles fields -->
|
||||
<div v-else>
|
||||
<label for="gearInitialMilesAddEdit"><b>* {{ $t("gearsAddEditUserModalComponent.addEditGearModalAddIsInitialMilesLabel") }}</b></label>
|
||||
<input class="form-control" type="number" step="0.1" name="gearInitialMilesAddEdit" v-model="newEditGearInitialMiles" required>
|
||||
</div>
|
||||
|
||||
<p>* {{ $t("generalItems.requiredField") }}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ $t("generalItems.buttonClose") }}</button>
|
||||
<button type="submit" class="btn btn-success" name="addGear" data-bs-dismiss="modal" v-if="action == 'add'" :disabled="!isNicknameExists">{{ $t("gearsAddEditUserModalComponent.addEditGearModalAddTitle") }}</button>
|
||||
<button type="submit" class="btn btn-success" name="addGear" data-bs-dismiss="modal" v-else :disabled="!isNicknameExists">{{ $t("gearsAddEditUserModalComponent.addEditGearModalEditTitle") }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
// Import the stores
|
||||
import { useAuthStore } from "@/stores/authStore";
|
||||
// import lodash
|
||||
import { debounce } from 'lodash';
|
||||
// Import Notivue push
|
||||
import { push } from "notivue";
|
||||
// Importing the services
|
||||
import { gears } from '@/services/gearsService';
|
||||
// Import units utils
|
||||
import { kmToMiles, milesToKm } from "@/utils/unitsUtils";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
action: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
gear: {
|
||||
type: Object,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
emits: ["isLoadingNewGear", "createdGear", "editedGear"],
|
||||
setup(props, { emit }) {
|
||||
const authStore = useAuthStore();
|
||||
const { t } = useI18n();
|
||||
// edit gear specific variables
|
||||
const editGearModalId = ref("");
|
||||
const newEditGearBrand = ref('');
|
||||
const newEditGearModel = ref('');
|
||||
const newEditGearNickname = ref('');
|
||||
const newEditGearType = ref(1);
|
||||
const newEditGearCreatedDate = ref(null);
|
||||
const newEditGearIsActive = ref(1);
|
||||
const newEditGearInitialKms = ref(0);
|
||||
const newEditGearInitialMiles = ref(0);
|
||||
const isNicknameExists = ref(true);
|
||||
const validateNicknameExists = debounce(async () => {
|
||||
let tryValidate = false;
|
||||
if (props.action === 'edit') {
|
||||
if (newEditGearNickname.value !== props.gear.nickname) {
|
||||
tryValidate = true;
|
||||
}
|
||||
} else {
|
||||
if (props.action === 'add') {
|
||||
if (newEditGearNickname.value !== "") {
|
||||
tryValidate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tryValidate) {
|
||||
try {
|
||||
if (await gears.getGearByNickname(newEditGearNickname.value)) {
|
||||
isNicknameExists.value = false;
|
||||
} else {
|
||||
isNicknameExists.value = true;
|
||||
}
|
||||
} catch (error) {
|
||||
push.error(`${t("generalItems.errorFetchingInfo")} - ${error}`);
|
||||
}
|
||||
} else {
|
||||
isNicknameExists.value = true;
|
||||
}
|
||||
}, 500);
|
||||
|
||||
if (props.gear) {
|
||||
if (props.action === 'edit') {
|
||||
editGearModalId.value = `editGearModal${props.gear.id}`;
|
||||
}
|
||||
newEditGearBrand.value = props.gear.brand;
|
||||
newEditGearModel.value = props.gear.model;
|
||||
newEditGearNickname.value = props.gear.nickname;
|
||||
newEditGearType.value = props.gear.type;
|
||||
newEditGearCreatedDate.value = props.gear.created_date;
|
||||
newEditGearIsActive.value = props.gear.is_active;
|
||||
newEditGearInitialKms.value = props.gear.initial_kms;
|
||||
if (props.gear.initial_kms && props.gear.initial_kms !== 0) {
|
||||
newEditGearInitialMiles.value = kmToMiles(props.gear.initial_kms);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function submitAddGearForm() {
|
||||
console.log('submitAddGearForm');
|
||||
// Set the loading variable to true.
|
||||
emit("isLoadingNewGear", true);
|
||||
try {
|
||||
// Create the gear data object.
|
||||
const data = {
|
||||
brand: newEditGearBrand.value,
|
||||
model: newEditGearModel.value,
|
||||
nickname: newEditGearNickname.value,
|
||||
gear_type: newEditGearType.value,
|
||||
created_at: newEditGearCreatedDate.value,
|
||||
is_active: newEditGearIsActive.value,
|
||||
initial_kms: newEditGearInitialKms.value,
|
||||
};
|
||||
|
||||
// Create the gear and get the created gear id.
|
||||
const createdGear = await gears.createGear(data);
|
||||
|
||||
// Set the loading variable to false.
|
||||
emit("isLoadingNewGear", false);
|
||||
|
||||
// Get the created gear and add it to the array.
|
||||
emit("createdGear", createdGear);
|
||||
|
||||
// Set the success message and show the success alert.
|
||||
push.success(t("gearsView.successGearAdded"));
|
||||
} catch (error) {
|
||||
// If there is an error, set the error message and show the error alert.
|
||||
push.error(`${t("generalItems.errorFetchingInfo")} - ${error}`);
|
||||
} finally {
|
||||
// Set the isLoadingNewGear variable to false.
|
||||
emit("isLoadingNewGear", false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function handleSubmit() {
|
||||
if (Number(authStore?.user?.units) === 1) {
|
||||
if ((props.gear && newEditGearInitialKms.value !== props.gear.initial_kms) || props.action === 'add') {
|
||||
newEditGearInitialMiles.value = kmToMiles(newEditGearInitialKms.initial_kms);
|
||||
}
|
||||
} else {
|
||||
if (props.action === 'add') {
|
||||
newEditGearInitialKms.value = milesToKm(newEditGearInitialMiles.value);
|
||||
} else {
|
||||
const miles = kmToMiles(props.gear.initial_kms);
|
||||
if (miles !== newEditGearInitialMiles.value) {
|
||||
newEditGearInitialKms.value = milesToKm(newEditGearInitialMiles.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (props.action === 'add') {
|
||||
submitAddGearForm();
|
||||
} else {
|
||||
submitEditGearForm();
|
||||
}
|
||||
}
|
||||
|
||||
// Watchers
|
||||
// Watch the newEditGearNickname variable.
|
||||
watch(newEditGearNickname, validateNicknameExists, { immediate: false });
|
||||
|
||||
return {
|
||||
authStore,
|
||||
t,
|
||||
editGearModalId,
|
||||
newEditGearBrand,
|
||||
newEditGearModel,
|
||||
newEditGearNickname,
|
||||
newEditGearType,
|
||||
newEditGearCreatedDate,
|
||||
newEditGearIsActive,
|
||||
newEditGearInitialKms,
|
||||
newEditGearInitialMiles,
|
||||
handleSubmit,
|
||||
isNicknameExists,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="addUserModal" v-if="action == 'add'">{{ $t("settingsUsersZone.buttonAddUser") }}</h1>
|
||||
<h1 class="modal-title fs-5" id="editUserModalId" v-else-if="action == 'edit'">{{ $t("usersAddEditUserModalComponent.addEditUserModalEditTitle") }}</h1>
|
||||
<h1 class="modal-title fs-5" :id='editUserModalId' v-else-if="action == 'edit'">{{ $t("usersAddEditUserModalComponent.addEditUserModalEditTitle") }}</h1>
|
||||
<h1 class="modal-title fs-5" id="editProfileModal" v-else>{{ $t("usersAddEditUserModalComponent.addEditUserModalEditProfileTitle") }}</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
@@ -412,15 +412,19 @@ export default {
|
||||
|
||||
function handleSubmit() {
|
||||
if (Number(authStore?.user?.units) === 1) {
|
||||
if (newEditUserHeightCms.value !== props.user.height) {
|
||||
if ((props.user && newEditUserHeightCms.value !== props.user.height) || props.action === 'add') {
|
||||
const { feet, inches } = cmToFeetInches(newEditUserHeightCms.value);
|
||||
newEditUserHeightFeet.value = feet;
|
||||
newEditUserHeightInches.value = inches;
|
||||
}
|
||||
} else {
|
||||
const { feet, inches } = cmToFeetInches(props.user.height);
|
||||
if (feet !== newEditUserHeightFeet.value || inches !== newEditUserHeightInches.value) {
|
||||
if (props.action === 'add') {
|
||||
newEditUserHeightCms.value = feetAndInchesToCm(newEditUserHeightFeet.value, newEditUserHeightInches.value);
|
||||
} else {
|
||||
const { feet, inches } = cmToFeetInches(props.user.height);
|
||||
if (feet !== newEditUserHeightFeet.value || inches !== newEditUserHeightInches.value) {
|
||||
newEditUserHeightCms.value = feetAndInchesToCm(newEditUserHeightFeet.value, newEditUserHeightInches.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
@@ -11,6 +11,8 @@ import caActivitySummaryComponent from './ca/components/activities/activitySumma
|
||||
import caEditActivityModalComponent from './ca/components/activities/modals/editActivityModalComponent.json';
|
||||
// Followers component
|
||||
import caFollowersListComponent from './ca/components/followers/followersListComponent.json';
|
||||
// Gears component
|
||||
import caGearsAddEditUserModalComponent from './ca/components/gears/gearsAddEditUserModalComponent.json';
|
||||
// Health components
|
||||
import caHealthWeightAddEditModalComponent from './ca/components/health/healthWeightZone/healthWeightAddEditModalComponent.json'
|
||||
import caHealthWeightListComponent from './ca/components/health/healthWeightZone/healthWeightListComponent.json'
|
||||
@@ -55,6 +57,8 @@ import deActivitySummaryComponent from './de/components/activities/activitySumma
|
||||
import deEditActivityModalComponent from './de/components/activities/modals/editActivityModalComponent.json';
|
||||
// Followers component
|
||||
import deFollowersListComponent from './de/components/followers/followersListComponent.json';
|
||||
// Gears component
|
||||
import deGearsAddEditUserModalComponent from './de/components/gears/gearsAddEditUserModalComponent.json';
|
||||
// Health components
|
||||
import deHealthWeightAddEditModalComponent from './de/components/health/healthWeightZone/healthWeightAddEditModalComponent.json'
|
||||
import deHealthWeightListComponent from './de/components/health/healthWeightZone/healthWeightListComponent.json'
|
||||
@@ -100,6 +104,8 @@ import frActivitySummaryComponent from './fr/components/activities/activitySumma
|
||||
import frEditActivityModalComponent from './fr/components/activities/modals/editActivityModalComponent.json';
|
||||
// Followers component
|
||||
import frFollowersListComponent from './fr/components/followers/followersListComponent.json';
|
||||
// Gears component
|
||||
import frGearsAddEditUserModalComponent from './fr/components/gears/gearsAddEditUserModalComponent.json';
|
||||
// Health components
|
||||
import frHealthWeightAddEditModalComponent from './fr/components/health/healthWeightZone/healthWeightAddEditModalComponent.json'
|
||||
import frHealthWeightListComponent from './fr/components/health/healthWeightZone/healthWeightListComponent.json'
|
||||
@@ -145,6 +151,8 @@ import ptActivitySummaryComponent from './pt/components/activities/activitySumma
|
||||
import ptEditActivityModalComponent from './pt/components/activities/modals/editActivityModalComponent.json';
|
||||
// Followers component
|
||||
import ptFollowersListComponent from './pt/components/followers/followersListComponent.json';
|
||||
// Gears component
|
||||
import ptGearsAddEditUserModalComponent from './pt/components/gears/gearsAddEditUserModalComponent.json';
|
||||
// Health components
|
||||
import ptHealthWeightAddEditModalComponent from './pt/components/health/healthWeightZone/healthWeightAddEditModalComponent.json'
|
||||
import ptHealthWeightListComponent from './pt/components/health/healthWeightZone/healthWeightListComponent.json'
|
||||
@@ -189,6 +197,8 @@ import usActivitySummaryComponent from './us/components/activities/activitySumma
|
||||
import usEditActivityModalComponent from './us/components/activities/modals/editActivityModalComponent.json';
|
||||
// Followers component
|
||||
import usFollowersListComponent from './us/components/followers/followersListComponent.json';
|
||||
// Gears component
|
||||
import usGearsAddEditUserModalComponent from './us/components/gears/gearsAddEditUserModalComponent.json';
|
||||
// Health components
|
||||
import usHealthWeightAddEditModalComponent from './us/components/health/healthWeightZone/healthWeightAddEditModalComponent.json'
|
||||
import usHealthWeightListComponent from './us/components/health/healthWeightZone/healthWeightListComponent.json'
|
||||
@@ -235,6 +245,8 @@ const messages = {
|
||||
editActivityModalComponent: caEditActivityModalComponent,
|
||||
// Followers component
|
||||
followersListComponent: caFollowersListComponent,
|
||||
// Gears component
|
||||
gearsAddEditUserModalComponent: caGearsAddEditUserModalComponent,
|
||||
// Health components
|
||||
healthWeightAddEditModalComponent: caHealthWeightAddEditModalComponent,
|
||||
healthSideBarComponent: caHealthSideBarComponent,
|
||||
@@ -279,6 +291,8 @@ const messages = {
|
||||
editActivityModalComponent: deEditActivityModalComponent,
|
||||
// Followers component
|
||||
followersListComponent: deFollowersListComponent,
|
||||
// Gears component
|
||||
gearsAddEditUserModalComponent: deGearsAddEditUserModalComponent,
|
||||
// Health components
|
||||
healthWeightAddEditModalComponent: deHealthWeightAddEditModalComponent,
|
||||
healthSideBarComponent: deHealthSideBarComponent,
|
||||
@@ -323,6 +337,8 @@ const messages = {
|
||||
editActivityModalComponent: frEditActivityModalComponent,
|
||||
// Followers component
|
||||
followersListComponent: frFollowersListComponent,
|
||||
// Gears component
|
||||
gearsAddEditUserModalComponent: frGearsAddEditUserModalComponent,
|
||||
// Health components
|
||||
healthWeightAddEditModalComponent: frHealthWeightAddEditModalComponent,
|
||||
healthSideBarComponent: frHealthSideBarComponent,
|
||||
@@ -367,6 +383,8 @@ const messages = {
|
||||
editActivityModalComponent: ptEditActivityModalComponent,
|
||||
// Followers component
|
||||
followersListComponent: ptFollowersListComponent,
|
||||
// Gears component
|
||||
gearsAddEditUserModalComponent: ptGearsAddEditUserModalComponent,
|
||||
// Health components
|
||||
healthWeightAddEditModalComponent: ptHealthWeightAddEditModalComponent,
|
||||
healthSideBarComponent: ptHealthSideBarComponent,
|
||||
@@ -411,6 +429,8 @@ const messages = {
|
||||
editActivityModalComponent: usEditActivityModalComponent,
|
||||
// Followers component
|
||||
followersListComponent: usFollowersListComponent,
|
||||
// Gears component
|
||||
gearsAddEditUserModalComponent: usGearsAddEditUserModalComponent,
|
||||
// Health components
|
||||
healthWeightAddEditModalComponent: usHealthWeightAddEditModalComponent,
|
||||
healthSideBarComponent: usHealthSideBarComponent,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"addEditGearModalEditTitle": "Edit gear",
|
||||
"addEditGearModalAddTitle": "Add gear",
|
||||
"addEditGearModalAddBrandLabel": "Brand",
|
||||
"addEditGearModalAddModelLabel": "Model",
|
||||
"addEditGearModalAddNicknameLabel": "Nickname",
|
||||
"addEditGearModalAddTypeLabel": "Gear type",
|
||||
"addEditGearModalAddTypeOption1": "Bike",
|
||||
"addEditGearModalAddTypeOption2": "Shoes",
|
||||
"addEditGearModalAddTypeOption3": "Wetsuit",
|
||||
"addEditGearModalAddDateLabel": "Created date",
|
||||
"addEditGearModalAddIsActiveLabel": "Is active",
|
||||
"addEditGearModalAddIsActiveOption1": "Active",
|
||||
"addEditGearModalAddIsActiveOption0": "Inactive",
|
||||
"addEditGearModalAddIsInitialKmsLabel": "Initial kms",
|
||||
"addEditGearModalAddIsInitialMilesLabel": "Initial miles"
|
||||
}
|
||||
@@ -4,15 +4,6 @@
|
||||
"subTitleSearchGearByNickname": "Search gear by nickname",
|
||||
"placeholderSearchGearByNickname": "Nickname",
|
||||
"buttonSearchGear": "Search Gear",
|
||||
"modalBrand": "Brand",
|
||||
"modalModel": "Model",
|
||||
"modalNickname": "Nickname",
|
||||
"modalGearTypeLabel": "Gear type",
|
||||
"modalGearTypeOption1Bike": "Bike",
|
||||
"modalGearTypeOption2Shoes": "Shoes",
|
||||
"modalGearTypeOption3Wetsuit": "Wetsuit",
|
||||
"modalDateLabel": "Created date",
|
||||
"modalDatePlaceholder": "Date",
|
||||
"displayUserNumberOfGears1": "There is a total of ",
|
||||
"displayUserNumberOfGears2": " gear(s) (",
|
||||
"displayUserNumberOfGears3": " loaded):",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"errorFetchingInfo": "Error fetching info",
|
||||
"errorEditingInfo": "Error editing info",
|
||||
"errorDeletingInfo": "Error deleting info",
|
||||
"errorNicknameAlreadyExistsFeedback": "Nickname already exists",
|
||||
"errorUsernameAlreadyExistsFeedback": "Username already exists",
|
||||
"errorEmailNotValidFeedback": "Email not valid",
|
||||
"errorEmailAlreadyExistsFeedback": "Email already exists",
|
||||
|
||||
@@ -7,6 +7,9 @@ export const gears = {
|
||||
getGearFromType(gearType) {
|
||||
return fetchGetRequest(`gears/type/${gearType}`);
|
||||
},
|
||||
getGearContainsNickname(nickname) {
|
||||
return fetchGetRequest(`gears/nickname/contains/${nickname}`);
|
||||
},
|
||||
getGearByNickname(nickname) {
|
||||
return fetchGetRequest(`gears/nickname/${nickname}`);
|
||||
},
|
||||
|
||||
@@ -33,6 +33,10 @@ export function feetAndInchesToCm(feet, inches) {
|
||||
return (totalInches * 2.54).toFixed(0);
|
||||
}
|
||||
|
||||
export function milesToKm(miles) {
|
||||
return (miles * 1.60934).toFixed(0);
|
||||
}
|
||||
|
||||
// Metric to Metric conversions
|
||||
export function metersToKm(meters) {
|
||||
return (meters / 1000).toFixed(2);
|
||||
|
||||
@@ -9,54 +9,7 @@
|
||||
</a>
|
||||
|
||||
<!-- Add gear modal -->
|
||||
<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">{{ $t("gearsView.buttonAddGear") }}</h1>
|
||||
<!--<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>-->
|
||||
</div>
|
||||
<form @submit.prevent="submitAddGearForm">
|
||||
<div class="modal-body">
|
||||
<!-- brand fields -->
|
||||
<label for="gearBrandAdd"><b>{{ $t("gearsView.modalBrand") }}</b></label>
|
||||
<input class="form-control" type="text" name="gearBrandAdd" :placeholder='$t("gearsView.modalBrand")' v-model="brand" maxlength="250">
|
||||
<!-- model fields -->
|
||||
<label for="gearModelAdd"><b>{{ $t("gearsView.modalModel") }}</b></label>
|
||||
<input class="form-control" type="text" name="gearModelAdd" :placeholder='$t("gearsView.modalModel")' v-model="model" maxlength="250">
|
||||
<!-- nickname fields -->
|
||||
<label for="gearNicknameAdd"><b>* {{ $t("gearsView.modalNickname") }}</b></label>
|
||||
<input class="form-control" type="text" name="gearNicknameAdd" :placeholder='$t("gearsView.modalNickname")' v-model="nickname" maxlength="250" required>
|
||||
<!-- gear type fields -->
|
||||
<label for="gearTypeAdd"><b>* {{ $t("gearsView.modalGearTypeLabel") }}</b></label>
|
||||
<select class="form-control" name="gearTypeAdd" v-model="gearType" required>
|
||||
<option value="1">{{ $t("gearsView.modalGearTypeOption1Bike") }}</option>
|
||||
<option value="2">{{ $t("gearsView.modalGearTypeOption2Shoes") }}</option>
|
||||
<option value="3">{{ $t("gearsView.modalGearTypeOption3Wetsuit") }}</option>
|
||||
</select>
|
||||
<!-- date fields -->
|
||||
<label for="gearDateAdd"><b>* {{ $t("gearsView.modalDateLabel") }}</b></label>
|
||||
<input class="form-control" type="date" name="gearDateAdd" :placeholder='$t("gearsView.modalDatePlaceholder")' v-model="date" required>
|
||||
<!-- gear is_active fields -->
|
||||
<label for="gearIsActiveAdd"><b>* {{ $t("gearsView.gearIsActiveLabel") }}</b></label>
|
||||
<select class="form-control" name="gearIsActiveAdd" v-model="isActive" required>
|
||||
<option value="1">{{ $t("gearsView.activeState") }}</option>
|
||||
<option value="0">{{ $t("gearsView.inactiveState") }}</option>
|
||||
</select>
|
||||
<!-- initial kilometers fields -->
|
||||
<label for="gearInitialKmsAdd"><b>* {{ $t("gearsView.initialKmsLabel") }}</b></label>
|
||||
<input class="form-control" type="number" step="0.2" name="gearInitialKmsAdd" v-model="initialKms" required>
|
||||
|
||||
<p>* {{ $t("generalItems.requiredField") }}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ $t("generalItems.buttonClose") }}</button>
|
||||
<button type="submit" class="btn btn-success" name="addGear" data-bs-dismiss="modal">{{ $t("gearsView.buttonAddGear") }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<GearsAddEditUserModalComponent :action="'add'" @createdGear="addGearList" @isLoadingNewGear="setIsLoadingNewGear"/>
|
||||
|
||||
<!-- Search gear by nickname zone -->
|
||||
<br>
|
||||
@@ -143,6 +96,7 @@ import NoItemsFoundComponent from '@/components/GeneralComponents/NoItemsFoundCo
|
||||
import LoadingComponent from '@/components/GeneralComponents/LoadingComponent.vue';
|
||||
import BackButtonComponent from '@/components/GeneralComponents/BackButtonComponent.vue';
|
||||
import PaginationComponent from '@/components/GeneralComponents/PaginationComponent.vue';
|
||||
import GearsAddEditUserModalComponent from '@/components/Gears/GearsAddEditUserModalComponent.vue';
|
||||
// Importing the services
|
||||
import { gears } from '@/services/gearsService';
|
||||
|
||||
@@ -154,17 +108,11 @@ export default {
|
||||
LoadingComponent,
|
||||
PaginationComponent,
|
||||
BackButtonComponent,
|
||||
GearsAddEditUserModalComponent,
|
||||
},
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const brand = ref('');
|
||||
const model = ref('');
|
||||
const nickname = ref('');
|
||||
const gearType = ref(1);
|
||||
const date = ref(null);
|
||||
const isActive = ref(1);
|
||||
const initialKms = ref(0);
|
||||
const isLoading = ref(true);
|
||||
const isGearsUpdatingLoading = ref(true);
|
||||
const isLoadingNewGear = ref(false)
|
||||
@@ -187,46 +135,11 @@ export default {
|
||||
}
|
||||
try {
|
||||
// Fetch the users based on the search nickname.
|
||||
userGears.value = await gears.getGearByNickname(searchNickname.value);
|
||||
userGears.value = await gears.getGearContainsNickname(searchNickname.value);
|
||||
} catch (error) {
|
||||
push.error(`${t("gearsView.errorGearNotFound")} - ${error}`);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
async function submitAddGearForm() {
|
||||
// Set the isLoadingNewGear variable to true.
|
||||
isLoadingNewGear.value = true;
|
||||
try {
|
||||
// Create the gear data object.
|
||||
const data = {
|
||||
brand: brand.value,
|
||||
model: model.value,
|
||||
nickname: nickname.value,
|
||||
gear_type: gearType.value,
|
||||
created_at: date.value,
|
||||
is_active: isActive.value,
|
||||
initial_kms: initialKms.value,
|
||||
};
|
||||
|
||||
// Create the gear and get the created gear id.
|
||||
const createdGearId = await gears.createGear(data);
|
||||
|
||||
// Get the created gear and add it to the userGears array.
|
||||
const newGear = await gears.getGearById(createdGearId);
|
||||
userGears.value.unshift(newGear);
|
||||
|
||||
userGearsNumber.value++;
|
||||
|
||||
// Set the success message and show the success alert.
|
||||
push.success(t("gearsView.successGearAdded"));
|
||||
} catch (error) {
|
||||
// If there is an error, set the error message and show the error alert.
|
||||
push.error(`${t("generalItems.errorFetchingInfo")} - ${error}`);
|
||||
} finally {
|
||||
// Set the isLoadingNewGear variable to false.
|
||||
isLoadingNewGear.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function setPageNumber(page) {
|
||||
// Set the page number.
|
||||
@@ -283,6 +196,20 @@ export default {
|
||||
isGearsUpdatingLoading.value = false;
|
||||
isLoading.value = false;
|
||||
});
|
||||
|
||||
function addGearList(createdGear) {
|
||||
userGears.value.unshift(createdGear);
|
||||
userGearsNumber.value++;
|
||||
}
|
||||
|
||||
function editUserList(editedGear) {
|
||||
const index = userGears.value.findIndex((user) => user.id === editedGear.id);
|
||||
userGears.value[index] = editedGear;
|
||||
}
|
||||
|
||||
function setIsLoadingNewGear(state) {
|
||||
isLoadingNewGear.value = state;
|
||||
}
|
||||
|
||||
// Watch the search nickname variable.
|
||||
watch(searchNickname, performSearch, { immediate: false });
|
||||
@@ -291,25 +218,20 @@ export default {
|
||||
watch(pageNumber, updateGears, { immediate: false });
|
||||
|
||||
return {
|
||||
brand,
|
||||
model,
|
||||
nickname,
|
||||
t,
|
||||
totalPages,
|
||||
pageNumber,
|
||||
numRecords,
|
||||
gearType,
|
||||
date,
|
||||
isActive,
|
||||
initialKms,
|
||||
isLoading,
|
||||
isGearsUpdatingLoading,
|
||||
isLoadingNewGear,
|
||||
userGears,
|
||||
userGearsNumber,
|
||||
searchNickname,
|
||||
t,
|
||||
submitAddGearForm,
|
||||
setPageNumber,
|
||||
addGearList,
|
||||
editUserList,
|
||||
setIsLoadingNewGear,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user