Skip to content

Commit 098ead8

Browse files
committed
change billable rate input to use shadcn component
1 parent d49082d commit 098ead8

File tree

5 files changed

+29
-80
lines changed

5 files changed

+29
-80
lines changed

resources/js/Components/Common/Member/MemberEditModal.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ const roleDescription = computed(() => {
154154
class="flex-1">
155155
<InputLabel
156156
for="memberBillableRate"
157-
class="mb-2"
158157
value="Billable Rate" />
159158
<BillableRateInput
160159
v-model="

resources/js/Components/Common/Project/ProjectEditModal.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ const project = ref<CreateProjectBody>({
4848
4949
async function submit() {
5050
if (props.originalProject.billable_rate !== project.value.billable_rate) {
51-
//
51+
// make sure that the alert modal is not immediately submitted when user presses enter
5252
setTimeout(() => {
5353
showBillableRateModal.value = true;
5454
}, 0);
@@ -133,7 +133,7 @@ async function submitBillableRate() {
133133
</ClientDropdown>
134134
</div>
135135
</div>
136-
<div class="lg:grid grid-cols-2 gap-12">
136+
<div>
137137
<div>
138138
<ProjectEditBillableSection
139139
v-model:is-billable="project.is_billable"

resources/js/packages/ui/src/Input/BillableRateInput.vue

Lines changed: 25 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,53 @@
11
<script setup lang="ts">
2-
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
3-
import { formatCents } from '@/packages/ui/src/utils/money';
4-
import { ref, watch, inject, type ComputedRef } from 'vue';
2+
import { ref } from 'vue';
53
import { useFocus } from '@vueuse/core';
6-
import type { Organization } from '@/packages/api/src';
4+
import {
5+
NumberField,
6+
NumberFieldContent,
7+
NumberFieldDecrement,
8+
NumberFieldIncrement,
9+
NumberFieldInput,
10+
} from '@/Components/ui/number-field';
711
812
const props = defineProps<{
913
name: string;
1014
focus?: boolean;
1115
currency: string;
1216
}>();
1317
14-
const organization = inject<ComputedRef<Organization>>('organization');
15-
1618
const model = defineModel<number | null>({
1719
default: null,
1820
});
1921
2022
const billableRateInput = ref<HTMLInputElement | null>(null);
2123
useFocus(billableRateInput, { initialValue: props.focus });
2224
23-
function cleanUpDecimalValue(value: string) {
24-
value = value.replace(/,/g, '');
25-
value = value.replace(props.currency, '');
26-
return value.replace(/\./g, '');
27-
}
28-
29-
function updateRate(value: string) {
30-
value = value.trim();
31-
if (value.includes(',')) {
32-
const parts = value.split(',');
33-
const lastPart = (parts[parts.length - 1] = parts[parts.length - 1]);
34-
if (lastPart.length === 2) {
35-
// we detected a decimal number with 2 digits after the comma
36-
value = cleanUpDecimalValue(value);
37-
model.value = parseInt(value);
38-
}
39-
} else if (value.includes('.')) {
40-
const parts = value.split('.');
41-
const lastPart = (parts[parts.length - 1] = parts[parts.length - 1]);
42-
if (lastPart.length === 2) {
43-
value = cleanUpDecimalValue(value);
44-
model.value = parseInt(value);
45-
}
46-
} else if (value === '') {
47-
model.value = 0;
48-
} else {
49-
// if it doesn't contain a comma or a dot, it's probably a whole number so let's convert it to cents
50-
const parsedValue = parseInt(cleanUpDecimalValue(value)) * 100;
51-
if (parsedValue) {
52-
model.value = parsedValue;
53-
} else {
54-
model.value = 0;
55-
}
56-
}
57-
inputValue.value = formatValue(model.value);
58-
}
59-
6025
function formatValue(modelValue: number | null) {
61-
const formattedValue = formatCents(
62-
modelValue ?? 0,
63-
props.currency,
64-
organization?.value?.currency_format,
65-
organization?.value?.currency_symbol,
66-
organization?.value?.number_format
67-
);
68-
return formattedValue
69-
?.replace(organization?.value?.currency_symbol ?? '', '')
70-
.trim();
26+
return modelValue ? modelValue / 100 : 0;
7127
}
72-
73-
watch(model, (newValue) => {
74-
inputValue.value = formatValue(newValue);
75-
});
76-
77-
const inputValue = ref(formatValue(model.value));
7828
</script>
7929

8030
<template>
8131
<div class="relative">
82-
<TextInput
32+
<NumberField
8333
:id="name"
8434
ref="billableRateInput"
85-
v-model="inputValue"
86-
type="text"
87-
:name="name"
88-
placeholder="Billable Rate"
35+
:model-value="formatValue(model)"
36+
:step-snapping="false"
8937
class="block w-full"
90-
autocomplete="teamMemberRate"
91-
@blur="updateRate($event.target.value)"
92-
@keydown.enter="updateRate($event.target.value)" />
93-
<div
94-
class="absolute top-0 right-0 h-full flex items-center px-4 font-medium pointer-events-none">
95-
<span>
96-
{{ currency }}
97-
</span>
98-
</div>
38+
:format-options="{
39+
style: 'currency',
40+
currency: currency,
41+
currencyDisplay: 'code',
42+
currencySign: 'accounting',
43+
}"
44+
@update:model-value="(value) => model = value * 100">
45+
<NumberFieldContent>
46+
<NumberFieldDecrement />
47+
<NumberFieldInput />
48+
<NumberFieldIncrement />
49+
</NumberFieldContent>
50+
</NumberField>
9951
</div>
10052
</template>
10153

resources/js/packages/ui/src/Project/ProjectCreateModal.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ const currentClientName = computed(() => {
128128
</ClientDropdown>
129129
</div>
130130
</div>
131-
<div class="lg:grid grid-cols-2 gap-12">
131+
<div>
132132
<div>
133133
<ProjectEditBillableSection
134134
v-model:is-billable="project.is_billable"

resources/js/packages/ui/src/Project/ProjectEditBillableSection.vue

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ const emit = defineEmits(['submit']);
6666
v-model="billableRateSelect"
6767
class="mt-2"></ProjectBillableSelect>
6868
</div>
69-
<div
70-
v-if="billableRateSelect === 'custom-rate'"
71-
class="sm:max-w-[120px]">
69+
<div v-if="billableRateSelect === 'custom-rate'">
7270
<InputLabel for="billableRate" value="Billable Rate" class="mb-2" />
7371
<BillableRateInput
7472
v-model="billableRate"

0 commit comments

Comments
 (0)