Skip to content

Commit

Permalink
Add busy state events to user components to disable button during loa…
Browse files Browse the repository at this point in the history
…ding
  • Loading branch information
SamuelWei committed Jan 24, 2025
1 parent 78f0c13 commit 0651cb8
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 36 deletions.
8 changes: 6 additions & 2 deletions resources/js/components/UserTabEmail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
<script setup>
import env from "../env";
import { useAuthStore } from "../stores/auth";
import { computed, onBeforeMount, ref } from "vue";
import { computed, onBeforeMount, ref, watch } from "vue";
import { useApi } from "../composables/useApi.js";
import { useUserPermissions } from "../composables/useUserPermission.js";
import { useFormErrors } from "../composables/useFormErrors.js";
Expand All @@ -106,7 +106,7 @@ const props = defineProps({
},
});
const emit = defineEmits(["updateUser", "notFoundError"]);
const emit = defineEmits(["updateUser", "notFoundError", "busy"]);
const api = useApi();
const userPermissions = useUserPermissions();
Expand All @@ -129,6 +129,10 @@ onBeforeMount(() => {
validationRequiredEmail.value = null;
});
watch(isBusy, () => {
emit("busy", isBusy.value);
});
function save(event) {
if (event) {
event.preventDefault();
Expand Down
6 changes: 5 additions & 1 deletion resources/js/components/UserTabOtherSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const props = defineProps({
},
});
const emit = defineEmits(["updateUser", "notFoundError", "staleError"]);
const emit = defineEmits(["updateUser", "notFoundError", "staleError", "busy"]);
const model = ref(null);
const isBusy = ref(false);
Expand All @@ -75,6 +75,10 @@ watch(
{ deep: true },
);
watch(isBusy, () => {
emit("busy", isBusy.value);
});
onBeforeMount(() => {
model.value = _.cloneDeep(props.user);
});
Expand Down
6 changes: 5 additions & 1 deletion resources/js/components/UserTabProfile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ const props = defineProps({
},
});
const emit = defineEmits(["updateUser", "notFoundError", "staleError"]);
const emit = defineEmits(["updateUser", "notFoundError", "staleError", "busy"]);
const isBusy = ref(false);
const model = ref({});
Expand All @@ -208,6 +208,10 @@ watch(
{ deep: true },
);
watch(isBusy, () => {
emit("busy", isBusy.value);
});
onBeforeMount(() => {
model.value = _.cloneDeep(props.user);
});
Expand Down
37 changes: 32 additions & 5 deletions resources/js/components/UserTabSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,30 @@
</template>
<Tabs v-if="!isBusy && user" value="base" scrollable lazy>
<TabList>
<Tab value="base" data-test="base-tab-button"
<Tab
value="base"
data-test="base-tab-button"
:disabled="isLoadingAction"
><i class="fa-solid fa-user mr-2" />
{{ $t("admin.users.base_data") }}</Tab
>
<Tab value="email" data-test="email-tab-button"
<Tab
value="email"
data-test="email-tab-button"
:disabled="isLoadingAction"
><i class="fa-solid fa-envelope mr-2" /> {{ $t("app.email") }}</Tab
>
<Tab value="security" data-test="security-tab-button"
<Tab
value="security"
data-test="security-tab-button"
:disabled="isLoadingAction"
><i class="fa-solid fa-user-shield mr-2" />
{{ $t("app.security") }}</Tab
>
<Tab value="others" data-test="others-tab-button"
<Tab
value="others"
data-test="others-tab-button"
:disabled="isLoadingAction"
><i class="fa-solid fa-user-gear mr-2" />
{{ $t("admin.users.other_settings") }}</Tab
>
Expand All @@ -30,6 +42,7 @@
@update-user="updateUser"
@stale-error="handleStaleError"
@not-found-error="handleNotFoundError"
@busy="(state) => (isLoadingAction = state)"
/>
</TabPanel>
<TabPanel value="email">
Expand All @@ -38,6 +51,7 @@
:view-only="viewOnly"
@update-user="updateUser"
@not-found-error="handleNotFoundError"
@busy="(state) => (isLoadingAction = state)"
/>
</TabPanel>
<TabPanel value="security">
Expand All @@ -47,6 +61,7 @@
@update-user="updateUser"
@stale-error="handleStaleError"
@not-found-error="handleNotFoundError"
@busy="(state) => (isLoadingAction = state)"
/>
</TabPanel>
<TabPanel value="others">
Expand All @@ -56,6 +71,7 @@
@update-user="updateUser"
@stale-error="handleStaleError"
@not-found-error="handleNotFoundError"
@busy="(state) => (isLoadingAction = state)"
/>
</TabPanel>
</TabPanels>
Expand Down Expand Up @@ -109,10 +125,11 @@ const props = defineProps({
},
});
const emit = defineEmits(["updateUser"]);
const emit = defineEmits(["updateUser", "busy", "loadingAction"]);
const user = ref(null);
const isBusy = ref(false);
const isLoadingAction = ref(false);
const loadingError = ref(false);
const staleError = ref({});
const modalVisible = ref(false);
Expand All @@ -125,6 +142,16 @@ onMounted(() => {
loadUser();
});
// detect busy status while data fetching and notify parent
watch(isBusy, () => {
console.log(isBusy.value);
emit("busy", isBusy.value);
});
watch(isLoadingAction, () => {
console.log(isLoadingAction.value);
emit("loadingAction", isLoadingAction.value);
});
function handleNotFoundError(error) {
router.push({ name: "admin.users" });
api.error(error);
Expand Down
19 changes: 16 additions & 3 deletions resources/js/components/UserTabSecurity.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
<UserTabSecurityRolesAndPermissionsSection
:user="user"
:view-only="viewOnly"
:disabled="isBusy"
@update-user="updateUser"
@stale-error="handleStaleError"
@not-found-error="handleNotFoundError"
@busy="(state) => (isBusy = state)"
/>
</AdminPanel>

Expand All @@ -16,21 +18,26 @@
>
<UserTabSecurityPasswordSection
:user="user"
:disabled="isBusy"
@update-user="updateUser"
@not-found-error="handleNotFoundError"
@busy="(state) => (isBusy = state)"
/>
</AdminPanel>

<AdminPanel v-if="isOwnUser" :title="$t('auth.sessions.active')">
<UserTabSecuritySessionsSection />
<UserTabSecuritySessionsSection
:disabled="isBusy"
@busy="(state) => (isBusy = state)"
/>
</AdminPanel>
</div>
</template>

<script setup>
import { useSettingsStore } from "../stores/settings";
import { useAuthStore } from "../stores/auth";
import { computed } from "vue";
import { computed, ref, watch } from "vue";
const props = defineProps({
user: {
Expand All @@ -43,11 +50,13 @@ const props = defineProps({
},
});
const emit = defineEmits(["staleError", "updateUser", "notFoundError"]);
const emit = defineEmits(["staleError", "updateUser", "notFoundError", "busy"]);

Check warning on line 53 in resources/js/components/UserTabSecurity.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/UserTabSecurity.vue#L53

Added line #L53 was not covered by tests
const authStore = useAuthStore();
const settingsStore = useSettingsStore();
const isBusy = ref(false);

Check warning on line 58 in resources/js/components/UserTabSecurity.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/UserTabSecurity.vue#L58

Added line #L58 was not covered by tests
const isOwnUser = computed(() => {
return authStore.currentUser?.id === props.user.id;
});
Expand All @@ -58,6 +67,10 @@ const canChangePassword = computed(() => {
);
});
watch(isBusy, () => {
emit("busy", isBusy.value);

Check warning on line 71 in resources/js/components/UserTabSecurity.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/UserTabSecurity.vue#L70-L71

Added lines #L70 - L71 were not covered by tests
});
function handleStaleError(error) {
emit("staleError", error);
}
Expand Down
20 changes: 14 additions & 6 deletions resources/js/components/UserTabSecurityPasswordSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
autocomplete="current-password"
type="password"
required
:disabled="isBusy"
:disabled="isBusy || disabled"
class="w-full"
:invalid="formErrors.fieldInvalid('current_password')"
/>
Expand All @@ -39,7 +39,7 @@
:autocomplete="isOwnUser ? 'new-password' : 'off'"
type="password"
required
:disabled="isBusy"
:disabled="isBusy || disabled"
class="w-full"
:invalid="formErrors.fieldInvalid('new_password')"
/>
Expand All @@ -63,7 +63,7 @@
:autocomplete="isOwnUser ? 'new-password' : 'off'"
type="password"
required
:disabled="isBusy"
:disabled="isBusy || disabled"
class="w-full"
:invalid="formErrors.fieldInvalid('new_password_confirmation')"
/>
Expand All @@ -74,7 +74,7 @@
</div>
<div class="flex justify-end">
<Button
:disabled="isBusy"
:disabled="isBusy || disabled"
type="submit"
:loading="isBusy"
:label="$t('auth.change_password')"
Expand All @@ -89,7 +89,7 @@
<script setup>
import env from "../env";
import { useAuthStore } from "../stores/auth";
import { computed, ref } from "vue";
import { computed, ref, watch } from "vue";
import { useApi } from "../composables/useApi.js";
import { useFormErrors } from "../composables/useFormErrors.js";
import { useToast } from "../composables/useToast.js";
Expand All @@ -100,9 +100,13 @@ const props = defineProps({
type: Object,
required: true,
},
disabled: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(["updateUser", "notFoundError"]);
const emit = defineEmits(["updateUser", "notFoundError", "busy"]);

Check warning on line 109 in resources/js/components/UserTabSecurityPasswordSection.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/UserTabSecurityPasswordSection.vue#L109

Added line #L109 was not covered by tests
const api = useApi();
const formErrors = useFormErrors();
Expand All @@ -119,6 +123,10 @@ const isOwnUser = computed(() => {
return authStore.currentUser?.id === props.user.id;
});
watch(isBusy, () => {
emit("busy", isBusy.value);

Check warning on line 127 in resources/js/components/UserTabSecurityPasswordSection.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/UserTabSecurityPasswordSection.vue#L126-L127

Added lines #L126 - L127 were not covered by tests
});
function changePassword(event) {
if (event) {
event.preventDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
aria-labelledby="roles-label"
:invalid="formErrors.fieldInvalid('roles', true)"
:disabled="
isBusy || viewOnly || !userPermissions.can('editUserRole', model)
isBusy ||
viewOnly ||
!userPermissions.can('editUserRole', model) ||
disabled
"
:automatic-roles="automaticRoles"
:disable-superuser="!authStore.currentUser.superuser"
Expand All @@ -26,7 +29,7 @@
<div class="flex justify-end">
<Button
v-if="!viewOnly && userPermissions.can('editUserRole', model)"
:disabled="isBusy || rolesLoadingError || rolesLoading"
:disabled="isBusy || rolesLoadingError || rolesLoading || disabled"
type="submit"
:loading="isBusy"
:label="$t('app.save')"
Expand Down Expand Up @@ -55,9 +58,13 @@ const props = defineProps({
type: Object,
required: true,
},
disabled: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(["staleError", "updateUser", "notFoundError"]);
const emit = defineEmits(["staleError", "updateUser", "notFoundError", "busy"]);

Check warning on line 67 in resources/js/components/UserTabSecurityRolesAndPermissionsSection.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/UserTabSecurityRolesAndPermissionsSection.vue#L67

Added line #L67 was not covered by tests
const userPermissions = useUserPermissions();
const api = useApi();
Expand Down Expand Up @@ -91,6 +98,10 @@ watch(
{ deep: true },
);
watch(isBusy, () => {
emit("busy", isBusy.value);

Check warning on line 102 in resources/js/components/UserTabSecurityRolesAndPermissionsSection.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/UserTabSecurityRolesAndPermissionsSection.vue#L101-L102

Added lines #L101 - L102 were not covered by tests
});
onBeforeMount(() => {
model.value = _.cloneDeep(props.user);
});
Expand Down
Loading

0 comments on commit 0651cb8

Please sign in to comment.