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
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:
@@ -66,14 +66,19 @@ import { loaSchema } from '@shared/schemas/loaSchema'
|
|||||||
import { toTypedSchema } from "@vee-validate/zod";
|
import { toTypedSchema } from "@vee-validate/zod";
|
||||||
import Calendar from "../ui/calendar/Calendar.vue";
|
import Calendar from "../ui/calendar/Calendar.vue";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
|
import Spinner from "../ui/spinner/Spinner.vue";
|
||||||
|
|
||||||
const { handleSubmit, values, resetForm } = useForm({
|
const { handleSubmit, values, resetForm } = useForm({
|
||||||
validationSchema: toTypedSchema(loaSchema),
|
validationSchema: toTypedSchema(loaSchema),
|
||||||
})
|
})
|
||||||
|
|
||||||
const formSubmitted = ref(false);
|
const formSubmitted = ref(false);
|
||||||
|
const submitting = ref(false);
|
||||||
|
|
||||||
const onSubmit = handleSubmit(async (values) => {
|
const onSubmit = handleSubmit(async (values) => {
|
||||||
|
//catch double submit
|
||||||
|
if (submitting.value) return;
|
||||||
|
submitting.value = true;
|
||||||
const out: LOARequest = {
|
const out: LOARequest = {
|
||||||
member_id: values.member_id,
|
member_id: values.member_id,
|
||||||
start_date: values.start_date,
|
start_date: values.start_date,
|
||||||
@@ -88,6 +93,7 @@ const onSubmit = handleSubmit(async (values) => {
|
|||||||
userStore.loadUser();
|
userStore.loadUser();
|
||||||
}
|
}
|
||||||
formSubmitted.value = true;
|
formSubmitted.value = true;
|
||||||
|
submitting.value = false;
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
@@ -325,7 +331,12 @@ const filteredMembers = computed(() => {
|
|||||||
</VeeField>
|
</VeeField>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div v-else class="flex flex-col gap-4 py-8 text-left">
|
<div v-else class="flex flex-col gap-4 py-8 text-left">
|
||||||
|
|||||||
@@ -31,8 +31,12 @@ const { handleSubmit, errors, values, resetForm, setFieldValue, submitCount } =
|
|||||||
validateOnMount: false,
|
validateOnMount: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const submitting = ref(false);
|
||||||
|
|
||||||
const submitForm = handleSubmit(
|
const submitForm = handleSubmit(
|
||||||
async (vals) => {
|
async (vals) => {
|
||||||
|
if (submitting.value) return;
|
||||||
|
submitting.value = true;
|
||||||
try {
|
try {
|
||||||
let output = vals;
|
let output = vals;
|
||||||
output.promotions.map(p => p.start_date = new Date(p.start_date).toISOString())
|
output.promotions.map(p => p.start_date = new Date(p.start_date).toISOString())
|
||||||
@@ -42,6 +46,8 @@ const submitForm = handleSubmit(
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
submitError.value = error;
|
submitError.value = error;
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
submitting.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -281,7 +287,12 @@ function setAllToday() {
|
|||||||
</VeeField>
|
</VeeField>
|
||||||
<div class="flex flex-col items-end gap-2">
|
<div class="flex flex-col items-end gap-2">
|
||||||
<div class="h-6" />
|
<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>
|
<p v-if="submitError" class="text-destructive">{{ submitError }}</p>
|
||||||
<div v-else class="h-6 flex justify-end">
|
<div v-else class="h-6 flex justify-end">
|
||||||
<p v-if="submitCount > 0 && errors.promotions && typeof errors.promotions === 'string'"
|
<p v-if="submitCount > 0 && errors.promotions && typeof errors.promotions === 'string'"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import Button from '../ui/button/Button.vue';
|
|||||||
import InputGroup from '../ui/input-group/InputGroup.vue';
|
import InputGroup from '../ui/input-group/InputGroup.vue';
|
||||||
import InputGroupAddon from '../ui/input-group/InputGroupAddon.vue';
|
import InputGroupAddon from '../ui/input-group/InputGroupAddon.vue';
|
||||||
import { SearchIcon } from 'lucide-vue-next';
|
import { SearchIcon } from 'lucide-vue-next';
|
||||||
|
import Spinner from '../ui/spinner/Spinner.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
allMembers: MemberLight[],
|
allMembers: MemberLight[],
|
||||||
@@ -43,8 +44,11 @@ function openDialog() {
|
|||||||
showAddMemberDialog.value = true;
|
showAddMemberDialog.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const submitting = ref(false);
|
||||||
async function handleAddMember() {
|
async function handleAddMember() {
|
||||||
|
//catch double submit
|
||||||
|
if (submitting.value) return;
|
||||||
|
submitting.value = true;
|
||||||
//guard
|
//guard
|
||||||
if (memberToAdd.value == null)
|
if (memberToAdd.value == null)
|
||||||
return;
|
return;
|
||||||
@@ -52,6 +56,7 @@ async function handleAddMember() {
|
|||||||
await addMemberToRole(memberToAdd.value.id, props.role.id);
|
await addMemberToRole(memberToAdd.value.id, props.role.id);
|
||||||
emit('submit');
|
emit('submit');
|
||||||
showAddMemberDialog.value = false;
|
showAddMemberDialog.value = false;
|
||||||
|
submitting.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -94,8 +99,11 @@ async function handleAddMember() {
|
|||||||
<Button variant="secondary" @click="showAddMemberDialog = false">
|
<Button variant="secondary" @click="showAddMemberDialog = false">
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button :disabled="!memberToAdd" @click="handleAddMember">
|
<Button :disabled="!memberToAdd || submitting" @click="handleAddMember">
|
||||||
Add
|
<span class="flex items-center gap-2" v-if="submitting">
|
||||||
|
<Spinner></Spinner> Add
|
||||||
|
</span>
|
||||||
|
<span v-else>Add</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
Reference in New Issue
Block a user