Client - edit a workout

This commit is contained in:
Sam
2021-09-28 12:39:12 +02:00
parent 3dbdd5cb6b
commit fab8cae3b2
15 changed files with 396 additions and 3 deletions

View File

@ -0,0 +1,67 @@
<template>
<div class="custom-textarea">
<textarea
:id="name"
:name="name"
:maxLenght="charLimit"
v-model="text"
@input="updateText"
/>
<div class="remaining-chars">
{{ t('workouts.REMAINING_CHARS') }}: {{ text.length }}/{{ charLimit }}
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
export default defineComponent({
name: 'CustomTextarea',
props: {
charLimit: {
type: Number,
default: 500,
},
input: {
type: String,
default: '',
},
name: {
type: String,
required: true,
},
},
emits: ['updateValue'],
setup(props, { emit }) {
const { t } = useI18n()
let text = ref('')
function updateText(event: Event & { target: HTMLInputElement }) {
emit('updateValue', event.target.value)
}
watch(
() => props.input,
(value) => {
text.value = value
}
)
return { t, text, updateText }
},
})
</script>
<style lang="scss" scoped>
@import '~@/scss/base.scss';
.custom-textarea {
display: flex;
flex-direction: column;
.remaining-chars {
font-size: 0.8em;
font-style: italic;
}
}
</style>

View File

@ -23,6 +23,16 @@
<div class="workout-title-date">
<div class="workout-title" v-if="workoutObject.type === 'WORKOUT'">
{{ workoutObject.title }}
<i
class="fa fa-edit"
aria-hidden="true"
@click="
$router.push({
name: 'EditWorkout',
params: { workoutId: workoutObject.workoutId },
})
"
/>
<i
class="fa fa-trash"
aria-hidden="true"
@ -135,6 +145,10 @@
.workout-link {
padding-left: $default-padding;
}
.fa {
padding: 0 $default-padding * 0.3;
}
}
}
</style>

View File

@ -0,0 +1,195 @@
<template>
<div id="workout-edition">
<Card :without-title="false">
<template #title>{{ t('workouts.EDIT_WORKOUT') }}</template>
<template #content>
<div id="workout-form">
<form @submit.prevent="updateWorkout">
<div class="form-items">
<div class="form-item">
<label> {{ t('workouts.SPORT', 1) }}: </label>
<select id="sport" v-model="workoutDataObject.sport_id">
<option
v-for="sport in translatedSports"
:value="sport.id"
:key="sport.id"
>
{{ sport.label }}
</option>
</select>
</div>
<div class="form-item">
<label for="title"> {{ t('workouts.TITLE') }}: </label>
<input
id="title"
name="title"
type="text"
v-model="workoutDataObject.title"
/>
</div>
<div class="form-item">
<label> {{ t('workouts.NOTES') }}: </label>
<CustomTextArea
name="notes"
:input="workoutDataObject.notes"
@updateValue="updateNotes"
/>
</div>
</div>
<ErrorMessage :message="errorMessages" v-if="errorMessages" />
<div class="form-buttons">
<button class="confirm" type="submit">
{{ t('buttons.SUBMIT') }}
</button>
<button
class="cancel"
@click="
$router.push({
name: 'Workout',
params: { workoutId: workout.id },
})
"
>
{{ t('buttons.CANCEL') }}
</button>
</div>
</form>
</div>
</template>
</Card>
</div>
</template>
<script lang="ts">
import {
ComputedRef,
PropType,
defineComponent,
computed,
reactive,
watch,
onUnmounted,
} from 'vue'
import { useI18n } from 'vue-i18n'
import Card from '@/components/Common/Card.vue'
import CustomTextArea from '@/components/Common/CustomTextArea.vue'
import ErrorMessage from '@/components/Common/ErrorMessage.vue'
import { ROOT_STORE, WORKOUTS_STORE } from '@/store/constants'
import { ISport } from '@/types/sports'
import { IWorkout } from '@/types/workouts'
import { useStore } from '@/use/useStore'
import { translateSports } from '@/utils/sports'
export default defineComponent({
name: 'AddOrEditWorkout',
components: {
Card,
CustomTextArea,
ErrorMessage,
},
props: {
sports: {
type: Object as PropType<ISport[]>,
required: true,
},
workout: {
type: Object as PropType<IWorkout>,
required: true,
},
},
setup(props) {
const { t } = useI18n()
const store = useStore()
const translatedSports: ComputedRef<ISport[]> = computed(() =>
translateSports(props.sports, t)
)
const errorMessages: ComputedRef<string | string[] | null> = computed(
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
)
const workoutForm = reactive({
sport_id: 0,
title: '',
notes: '',
})
function updateNotes(value: string) {
workoutForm.notes = value
}
function updateWorkout() {
if (props.workout) {
store.dispatch(WORKOUTS_STORE.ACTIONS.EDIT_WORKOUT, {
workoutId: props.workout.id,
data: workoutForm,
})
}
}
watch(
() => props.workout,
async (newWorkout: IWorkout | undefined) => {
if (newWorkout && newWorkout.id) {
workoutForm.sport_id = newWorkout.sport_id
workoutForm.title = newWorkout.title
workoutForm.notes = newWorkout.notes
}
}
)
onUnmounted(() => store.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES))
return {
errorMessages,
t,
translatedSports,
workoutDataObject: workoutForm,
updateNotes,
updateWorkout,
}
},
})
</script>
<style lang="scss" scoped>
@import '~@/scss/base';
#workout-edition {
margin: 25% auto;
width: 700px;
::v-deep(.card) {
.card-title {
text-align: center;
text-transform: uppercase;
}
.card-content {
.form-items {
display: flex;
flex-direction: column;
.form-item {
display: flex;
flex-direction: column;
padding: $default-padding;
label {
text-transform: capitalize;
}
}
}
.form-buttons {
display: flex;
justify-content: flex-end;
button {
margin: $default-padding * 0.5;
}
}
}
}
@media screen and (max-width: $small-limit) {
width: 100%;
}
}
</style>