Merge pull request '155-Prevent-multi-submit' (#156) from 155-Prevent-multi-submit into main
All checks were successful
Continuous Integration / Update Development (push) Successful in 2m59s

Reviewed-on: #156
This commit was merged in pull request #156.
This commit is contained in:
2026-01-19 18:03:51 -06:00
3 changed files with 35 additions and 5 deletions

View File

@@ -66,14 +66,19 @@ import { loaSchema } from '@shared/schemas/loaSchema'
import { toTypedSchema } from "@vee-validate/zod";
import Calendar from "../ui/calendar/Calendar.vue";
import { useUserStore } from "@/stores/user";
import Spinner from "../ui/spinner/Spinner.vue";
const { handleSubmit, values, resetForm } = useForm({
validationSchema: toTypedSchema(loaSchema),
})
const formSubmitted = ref(false);
const submitting = ref(false);
const onSubmit = handleSubmit(async (values) => {
//catch double submit
if (submitting.value) return;
submitting.value = true;
const out: LOARequest = {
member_id: values.member_id,
start_date: values.start_date,
@@ -88,6 +93,7 @@ const onSubmit = handleSubmit(async (values) => {
userStore.loadUser();
}
formSubmitted.value = true;
submitting.value = false;
})
onMounted(async () => {
@@ -325,7 +331,12 @@ const filteredMembers = computed(() => {
</VeeField>
</div>
<div class="flex justify-end">
<Button type="submit">Submit</Button>
<Button type="submit" :disabled="submitting" class="w-35">
<span class="flex items-center gap-2" v-if="submitting">
<Spinner></Spinner> Submitting…
</span>
<span v-else>Submit</span>
</Button>
</div>
</form>
<div v-else class="flex flex-col gap-4 py-8 text-left">

View File

@@ -31,8 +31,12 @@ const { handleSubmit, errors, values, resetForm, setFieldValue, submitCount } =
validateOnMount: false,
})
const submitting = ref(false);
const submitForm = handleSubmit(
async (vals) => {
if (submitting.value) return;
submitting.value = true;
try {
let output = vals;
output.promotions.map(p => p.start_date = new Date(p.start_date).toISOString())
@@ -42,6 +46,8 @@ const submitForm = handleSubmit(
} catch (error) {
submitError.value = error;
console.error(error);
} finally {
submitting.value = false;
}
}
);
@@ -281,7 +287,12 @@ function setAllToday() {
</VeeField>
<div class="flex flex-col items-end gap-2">
<div class="h-6" />
<Button type="submit" class="w-min">Submit</Button>
<Button type="submit" form="trainingForm" :disabled="submitting" class="w-35">
<span class="flex items-center gap-2" v-if="submitting">
<Spinner></Spinner> Submitting…
</span>
<span v-else>Submit</span>
</Button>
<p v-if="submitError" class="text-destructive">{{ submitError }}</p>
<div v-else class="h-6 flex justify-end">
<p v-if="submitCount > 0 && errors.promotions && typeof errors.promotions === 'string'"

View File

@@ -13,6 +13,7 @@ import Button from '../ui/button/Button.vue';
import InputGroup from '../ui/input-group/InputGroup.vue';
import InputGroupAddon from '../ui/input-group/InputGroupAddon.vue';
import { SearchIcon } from 'lucide-vue-next';
import Spinner from '../ui/spinner/Spinner.vue';
const props = defineProps<{
allMembers: MemberLight[],
@@ -43,8 +44,11 @@ function openDialog() {
showAddMemberDialog.value = true;
}
const submitting = ref(false);
async function handleAddMember() {
//catch double submit
if (submitting.value) return;
submitting.value = true;
//guard
if (memberToAdd.value == null)
return;
@@ -52,6 +56,7 @@ async function handleAddMember() {
await addMemberToRole(memberToAdd.value.id, props.role.id);
emit('submit');
showAddMemberDialog.value = false;
submitting.value = false;
}
</script>
@@ -94,8 +99,11 @@ async function handleAddMember() {
<Button variant="secondary" @click="showAddMemberDialog = false">
Cancel
</Button>
<Button :disabled="!memberToAdd" @click="handleAddMember">
Add
<Button :disabled="!memberToAdd || submitting" @click="handleAddMember">
<span class="flex items-center gap-2" v-if="submitting">
<Spinner></Spinner> Add
</span>
<span v-else>Add</span>
</Button>
</DialogFooter>
</DialogContent>