Skip to content

Commit

Permalink
Use validation rule in password form
Browse files Browse the repository at this point in the history
  • Loading branch information
tonioo committed Feb 21, 2024
1 parent be11bc7 commit 29d9253
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 92 deletions.
31 changes: 15 additions & 16 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: local
- repo: local
hooks:
- id: pylint
- id: pylint
name: pylint
entry: pylint
language: system
types: [python]
args:
[
"-rn",
"-sn",
"--fail-under=5"
]
- repo: https://github.com/psf/black
rev: '24.2.0'
args: ["-rn", "-sn", "--fail-under=5"]
- repo: https://github.com/psf/black
rev: "24.2.0"
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-eslint
rev: 'v9.0.0-beta.0'
- id: black
- repo: https://github.com/pre-commit/mirrors-eslint
rev: "v9.0.0-beta.0"
hooks:
- id: eslint
- id: eslint
files: \.(js|vue)$
types: [file]
additional_dependencies:
- eslint
- eslint-plugin-vue
- eslint
- eslint-plugin-vue
- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v4.0.0-alpha.8" # Use the sha / tag you want to point at
hooks:
- id: prettier
2 changes: 1 addition & 1 deletion frontend/.editorconfig
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<template>
<div>
<template v-if="withPasswordCheck">
<label class="m-label">{{ $gettext('Current password') }}</label>
<label class="m-label">{{ $gettext("Current password") }}</label>
<v-text-field
v-model="account.currentPassword"
autocomplete="new-password"
variant="outlined"
type="password"
density="compact"
validate-on="submit"
:rules="disabled ? [] : [rules.required]"
:rules="disabled ? [] : [rules.required, validPassword]"
:disabled="disabled"
/>
</template>
Expand Down Expand Up @@ -73,58 +74,58 @@
</template>

<script setup lang="js">
import { useBusStore } from '@/stores'
import accountsApi from '@/api/accounts'
import accountApi from '@/api/account'
import { computed } from 'vue'
import rules from '@/plugins/rules'
import { useGettext } from 'vue3-gettext'
import { useBusStore } from "@/stores";
import accountsApi from "@/api/accounts";
import accountApi from "@/api/account";
import { computed } from "vue";
import rules from "@/plugins/rules";
import { useGettext } from "vue3-gettext";
const { $gettext } = useGettext()
const busStore = useBusStore()
const { $gettext } = useGettext();
const busStore = useBusStore();
const props = defineProps({
modelValue: { type: Object, default: null },
withPasswordCheck: { type: Boolean, default: false },
disabled: { type: Boolean, default: false },
editing: { type: Boolean, default: false },
formErrors: { type: Object, required: false, default: () => {} },
})
});
const account = computed(() => props.modelValue)
const account = computed(() => props.modelValue);
const isRuleActive = computed(
() => !props.disabled && (!props.editing || account.value.password)
)
() => !props.disabled && (!props.editing || account.value.password),
);
const passwordConfirmationRules = (value) =>
value === account.value.password || $gettext('Password mismatch')
value === account.value.password || $gettext("Password mismatch");
function copyPassword() {
navigator.clipboard.writeText(account.value.password).then(() => {
busStore.displayNotification({
msg: $gettext('Password copied to clipboard'),
})
})
msg: $gettext("Password copied to clipboard"),
});
});
}
function updatePassword(value) {
if (value) {
accountsApi.getRandomPassword().then((resp) => {
account.value.password = resp.data.password
})
account.value.password = resp.data.password;
});
} else {
account.value.password = null
account.value.password_confirmation = null
account.value.password = null;
account.value.password_confirmation = null;
}
}
async function validPassword() {
if (account.value.password) {
async function validPassword(value) {
if (value) {
return accountApi
.checkPassword(account.value.password)
.checkPassword(value)
.then(() => true)
.catch(() => $gettext('Invalid password'))
.catch(() => $gettext("Invalid password"));
}
return true
return true;
}
</script>
107 changes: 59 additions & 48 deletions frontend/src/components/tools/ChoiceField.vue
Original file line number Diff line number Diff line change
@@ -1,101 +1,112 @@
<template>
<div class="text-subtitle-1 text-grey-darken-1 mb-5" :class="{ 'label--disabled': disabled }">
<div
class="text-subtitle-1 text-grey-darken-1 mb-5"
:class="{ 'label--disabled': disabled }"
>
<label class="m-label">{{ label }}</label>
</div>
<div class="d-flex" v-for="(lineChoices, index1) in formatedChoices" :key="index1">
<div v-for="(choice, index2) in lineChoices"
:key="index2"
class="choice rounded pa-10 mr-4 text-center flex-grow-0 mb-4"
:class="{ 'choice--disabled': disabled, 'choice--selected': !disabled && currentChoice === choice.value }"
@click="selectChoice(choice.value)"
>
<div
v-for="(lineChoices, index1) in formatedChoices"
:key="index1"
class="d-flex"
>
<div
v-for="(choice, index2) in lineChoices"
:key="index2"
class="choice rounded pa-10 mr-4 text-center flex-grow-0 mb-4"
:class="{
'choice--disabled': disabled,
'choice--selected': !disabled && currentChoice === choice.value,
}"
@click="selectChoice(choice.value)"
>
<v-icon
v-if="choice.icon"
class="d-block mb-2 mx-auto"
:color="iconColor(choice.value)"
size="x-large"
:icon="choice.icon"
v-if="choice.icon"
class="d-block mb-2 mx-auto"
:color="iconColor(choice.value)"
size="x-large"
:icon="choice.icon"
/>
<span class="text-grey-darken-1">{{ choice.label }}</span>
</div>
</div>
</template>

<script setup lang="js">
import { ref, onMounted, computed } from 'vue'
import { ref, onMounted, computed } from "vue";
const props = defineProps({
modelValue: { type: [Number, String], default: null },
label: { type: String, default: '' },
label: { type: String, default: "" },
choices: { type: Array, default: () => [] },
disabled: {
type: Boolean,
default: false,
},
choicesPerLine: { type: Number, default: undefined },
})
});
const emit = defineEmits(['update:modelValue'])
const emit = defineEmits(["update:modelValue"]);
const currentChoice = computed({
get() {
return props.modelValue
return props.modelValue;
},
set(value) {
emit('update:modelValue', value)
emit("update:modelValue", value);
},
})
});
const formatedChoices = ref([])
const formatedChoices = ref([]);
function formatChoices() {
if (props.choicesPerLine) {
let sliceIndex = 0
let sliceIndex = 0;
while (sliceIndex < props.choices.length) {
const result = props.choices.slice(
sliceIndex,
sliceIndex + props.choicesPerLine
)
formatedChoices.value.push(result)
sliceIndex += props.choicesPerLine
sliceIndex + props.choicesPerLine,
);
formatedChoices.value.push(result);
sliceIndex += props.choicesPerLine;
}
} else {
formatedChoices.value.push(props.choices)
formatedChoices.value.push(props.choices);
}
}
function iconColor(value) {
return !props.disabled && value === currentChoice.value ? 'primary' : ''
return !props.disabled && value === currentChoice.value ? "primary" : "";
}
function selectChoice(value) {
if (props.disabled) {
return
return;
}
currentChoice.value = value
currentChoice.value = value;
}
onMounted(() => {
formatChoices()
})
formatChoices();
});
</script>

<style lang="scss" scoped>
.choice {
flex-basis: 200px;
background-color: #f2f5f7;
border: 1px solid #dbdddf;
cursor: pointer;
.choice {
flex-basis: 200px;
background-color: #f2f5f7;
border: 1px solid #dbdddf;
cursor: pointer;
&--selected {
border-color: #046bf8 !important;
}
&--selected {
border-color: #046bf8 !important;
}
&--disabled {
cursor: unset;
opacity: 0.5;
}
}
.label--disabled {
opacity: 0.5;
}
&--disabled {
cursor: unset;
opacity: 0.5;
}
}
.label--disabled {
opacity: 0.5;
}
</style>

0 comments on commit 29d9253

Please sign in to comment.