mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-15 19:52:15 +01:00
move ui and api to seperate packages and add npm actions for them
This commit is contained in:
@@ -1,48 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import Badge from '@/Components/Common/Badge.vue';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
name: string;
|
||||
size: 'base' | 'large' | 'xlarge';
|
||||
tag: string;
|
||||
class?: string;
|
||||
color: string;
|
||||
border: boolean;
|
||||
}>(),
|
||||
{
|
||||
name: '',
|
||||
size: 'base',
|
||||
tag: 'div',
|
||||
color: 'var(--theme-color-icon-default)',
|
||||
border: true,
|
||||
}
|
||||
);
|
||||
|
||||
const indicatorClasses = {
|
||||
base: 'w-2.5 h-2.5',
|
||||
large: 'w-2 sm:w-3 h-2 sm:h-3',
|
||||
xlarge: 'w-3 sm:w-4 h-3 sm:h-4',
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Badge :name :size :tag :class="props.class" :color :border>
|
||||
<div
|
||||
:style="{ backgroundColor: props.color }"
|
||||
:class="
|
||||
twMerge(
|
||||
indicatorClasses[size],
|
||||
'inline-block rounded-full shrink-0'
|
||||
)
|
||||
"></div>
|
||||
<div class="min-w-0">
|
||||
<slot>
|
||||
{{ name }}
|
||||
</slot>
|
||||
</div>
|
||||
</Badge>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,40 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { formatCents } from '../../../utils/money';
|
||||
import BillableRateModal from '@/Components/Common/BillableRateModal.vue';
|
||||
|
||||
const show = defineModel('show', { default: false });
|
||||
const saving = defineModel('saving', { default: false });
|
||||
|
||||
defineProps<{
|
||||
newBillableRate?: number | null;
|
||||
projectName: string;
|
||||
}>();
|
||||
|
||||
defineEmits<{
|
||||
submit: [];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BillableRateModal
|
||||
@submit="$emit('submit')"
|
||||
v-model:show="show"
|
||||
v-model:saving="saving"
|
||||
title="Update Project Billable Rate">
|
||||
<p class="py-1 text-center">
|
||||
The billable rate of {{ projectName }} will be updated to
|
||||
<strong>{{
|
||||
newBillableRate
|
||||
? formatCents(newBillableRate)
|
||||
: ' the default rate of the organization member'
|
||||
}}</strong
|
||||
>.
|
||||
</p>
|
||||
<p class="py-1 text-center font-semibold max-w-md mx-auto">
|
||||
Do you want to update all existing time entries, where the project
|
||||
billable rate applies as well?
|
||||
</p>
|
||||
</BillableRateModal>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,62 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import SelectDropdown from '@/Components/Common/SelectDropdown.vue';
|
||||
import Badge from '@/Components/Common/Badge.vue';
|
||||
import { ChevronDownIcon } from '@heroicons/vue/20/solid';
|
||||
import type { BillableKey } from '@/types/projects';
|
||||
|
||||
const model = defineModel<BillableKey>({
|
||||
default: 'non-billable',
|
||||
});
|
||||
|
||||
type Option = { key: BillableKey; name: string };
|
||||
|
||||
const options: Option[] = [
|
||||
{
|
||||
key: 'non-billable',
|
||||
name: 'Non-billable',
|
||||
},
|
||||
{
|
||||
key: 'default-rate',
|
||||
name: 'Default Rate',
|
||||
},
|
||||
{
|
||||
key: 'custom-rate',
|
||||
name: 'Custom Rate',
|
||||
},
|
||||
];
|
||||
|
||||
function getKeyFromItem(item: Option) {
|
||||
return item.key;
|
||||
}
|
||||
|
||||
function getNameFromItem(item: Option) {
|
||||
return item.name;
|
||||
}
|
||||
|
||||
function getNameForKey(key: BillableKey | undefined) {
|
||||
const item = options.find((item) => getKeyFromItem(item) === key);
|
||||
if (item) {
|
||||
return getNameFromItem(item);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectDropdown
|
||||
v-model="model"
|
||||
:get-key-from-item="getKeyFromItem"
|
||||
:get-name-for-item="getNameFromItem"
|
||||
:items="options">
|
||||
<template #trigger>
|
||||
<Badge size="xlarge" class="bg-input-background cursor-pointer">
|
||||
<span>
|
||||
{{ getNameForKey(model) }}
|
||||
</span>
|
||||
<ChevronDownIcon class="text-muted w-5"></ChevronDownIcon>
|
||||
</Badge>
|
||||
</template>
|
||||
</SelectDropdown>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,38 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import Dropdown from '@/Components/Dropdown.vue';
|
||||
import { colors } from '@/utils/color';
|
||||
|
||||
const model = defineModel<string>({ default: '' });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Dropdown align="bottom">
|
||||
<template #trigger>
|
||||
<button
|
||||
class="p-2 bg-input-background hover:bg-tertiary transition rounded-full border border-input-border">
|
||||
<div
|
||||
:style="{
|
||||
backgroundColor: model,
|
||||
}"
|
||||
class="w-6 h-6 rounded-full cursor-pointer"></div>
|
||||
</button>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="text-white grid grid-cols-6 gap-3 px-3 py-3">
|
||||
<div
|
||||
v-for="color in colors"
|
||||
:key="color"
|
||||
@click="model = color"
|
||||
:style="{
|
||||
backgroundColor: color,
|
||||
boxShadow: `var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) ${color}30`,
|
||||
}"
|
||||
class="w-4 h-4 rounded-full cursor-pointer"></div>
|
||||
</div>
|
||||
</template>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,136 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import TextInput from '@/Components/TextInput.vue';
|
||||
import SecondaryButton from '@/Components/SecondaryButton.vue';
|
||||
import DialogModal from '@/Components/DialogModal.vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import type { CreateClientBody, CreateProjectBody, Project } from '@/utils/api';
|
||||
import { getRandomColor } from '@/utils/color';
|
||||
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
||||
import { useFocus } from '@vueuse/core';
|
||||
import ClientDropdown from '@/Components/Common/Client/ClientDropdown.vue';
|
||||
import Badge from '@/Components/Common/Badge.vue';
|
||||
import ProjectColorSelector from '@/Components/Common/Project/ProjectColorSelector.vue';
|
||||
import { UserCircleIcon } from '@heroicons/vue/20/solid';
|
||||
import InputLabel from '@/Components/InputLabel.vue';
|
||||
import ProjectEditBillableSection from '@/Components/Common/Project/ProjectEditBillableSection.vue';
|
||||
import type { Client } from '@/utils/api';
|
||||
|
||||
const show = defineModel('show', { default: false });
|
||||
const saving = ref(false);
|
||||
|
||||
const props = defineProps<{
|
||||
clients: Client[];
|
||||
createProject: (project: CreateProjectBody) => Promise<Project | undefined>;
|
||||
createClient: (client: CreateClientBody) => Promise<Client | undefined>;
|
||||
}>();
|
||||
|
||||
const project = ref<CreateProjectBody>({
|
||||
name: '',
|
||||
color: getRandomColor(),
|
||||
client_id: null,
|
||||
billable_rate: null,
|
||||
is_billable: false,
|
||||
});
|
||||
|
||||
async function submit() {
|
||||
await props.createProject(project.value);
|
||||
show.value = false;
|
||||
project.value = {
|
||||
name: '',
|
||||
color: getRandomColor(),
|
||||
client_id: null,
|
||||
billable_rate: null,
|
||||
is_billable: false,
|
||||
};
|
||||
}
|
||||
|
||||
const projectNameInput = ref<HTMLInputElement | null>(null);
|
||||
|
||||
useFocus(projectNameInput, { initialValue: true });
|
||||
|
||||
const currentClientName = computed(() => {
|
||||
if (project.value.client_id) {
|
||||
return props.clients.find(
|
||||
(client) => client.id === project.value.client_id
|
||||
)?.name;
|
||||
}
|
||||
return 'No Client';
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogModal closeable :show="show" @close="show = false">
|
||||
<template #title>
|
||||
<div class="flex space-x-2">
|
||||
<span> Create Project </span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div
|
||||
class="sm:flex items-center space-y-2 sm:space-y-0 sm:space-x-4">
|
||||
<div class="flex-1 flex items-center">
|
||||
<div class="text-center pr-5">
|
||||
<InputLabel for="color" value="Color" />
|
||||
<ProjectColorSelector
|
||||
class="mt-2.5"
|
||||
v-model="project.color"></ProjectColorSelector>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<InputLabel for="projectName" value="Project name" />
|
||||
<TextInput
|
||||
id="projectName"
|
||||
name="projectName"
|
||||
ref="projectNameInput"
|
||||
v-model="project.name"
|
||||
type="text"
|
||||
placeholder="The next big thing"
|
||||
@keydown.enter="submit()"
|
||||
class="mt-2 block w-full"
|
||||
required
|
||||
autocomplete="projectName" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<InputLabel for="client" value="Client" />
|
||||
<ClientDropdown
|
||||
:createClient="createClient"
|
||||
:clients="clients"
|
||||
class="mt-2"
|
||||
v-model="project.client_id">
|
||||
<template #trigger>
|
||||
<Badge
|
||||
class="bg-input-background cursor-pointer hover:bg-tertiary"
|
||||
size="xlarge">
|
||||
<div class="flex items-center space-x-2">
|
||||
<UserCircleIcon
|
||||
class="w-5 text-icon-default"></UserCircleIcon>
|
||||
<span>
|
||||
{{ currentClientName }}
|
||||
</span>
|
||||
</div>
|
||||
</Badge>
|
||||
</template>
|
||||
</ClientDropdown>
|
||||
</div>
|
||||
</div>
|
||||
<ProjectEditBillableSection
|
||||
v-model:isBillable="project.is_billable"
|
||||
v-model:billableRate="
|
||||
project.billable_rate
|
||||
"></ProjectEditBillableSection>
|
||||
</template>
|
||||
<template #footer>
|
||||
<SecondaryButton @click="show = false"> Cancel</SecondaryButton>
|
||||
<PrimaryButton
|
||||
class="ms-3"
|
||||
:class="{ 'opacity-25': saving }"
|
||||
:disabled="saving"
|
||||
@click="submit">
|
||||
Create Project
|
||||
</PrimaryButton>
|
||||
</template>
|
||||
</DialogModal>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import ProjectBadge from '@/Components/Common/Project/ProjectBadge.vue';
|
||||
import ProjectBadge from '@/packages/ui/src/Project/ProjectBadge.vue';
|
||||
import { computed, nextTick, ref, watch } from 'vue';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import Dropdown from '@/Components/Dropdown.vue';
|
||||
import Dropdown from '@/packages/ui/src/Input/Dropdown.vue';
|
||||
import {
|
||||
ComboboxAnchor,
|
||||
ComboboxContent,
|
||||
@@ -12,12 +12,12 @@ import {
|
||||
ComboboxViewport,
|
||||
} from 'radix-vue';
|
||||
import { PlusCircleIcon } from '@heroicons/vue/20/solid';
|
||||
import ProjectDropdownItem from '@/Components/Common/Project/ProjectDropdownItem.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { api } from '@/utils/api';
|
||||
import { api } from '@/packages/api/src';
|
||||
import { usePage } from '@inertiajs/vue3';
|
||||
import { getRandomColor } from '@/utils/color';
|
||||
import type { Project } from '@/utils/api';
|
||||
import { getRandomColor } from '@/packages/ui/src/utils/color';
|
||||
import type { Project } from '@/packages/api/src';
|
||||
import ProjectDropdownItem from '@/packages/ui/src/Project/ProjectDropdownItem.vue';
|
||||
|
||||
const searchValue = ref('');
|
||||
const searchInput = ref<HTMLElement | null>(null);
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
name: string;
|
||||
selected: boolean;
|
||||
color: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center space-x-3 w-full px-3 py-2.5 text-start text-sm font-medium leading-5 text-white hover:bg-card-background-active focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out">
|
||||
<div
|
||||
:style="{ backgroundColor: color }"
|
||||
class="w-3 h-3 rounded-full"></div>
|
||||
<span>{{ name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,78 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import InputLabel from '@/Components/InputLabel.vue';
|
||||
import BillableRateInput from '@/Components/Common/BillableRateInput.vue';
|
||||
import ProjectBillableSelect from '@/Components/Common/Project/ProjectBillableSelect.vue';
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import type { BillableKey } from '@/types/projects';
|
||||
|
||||
const billableRateSelect = ref<BillableKey>('non-billable');
|
||||
|
||||
const billableRate = defineModel<number | null>('billableRate');
|
||||
const isBillable = defineModel<boolean>('isBillable');
|
||||
|
||||
onMounted(() => {
|
||||
if (isBillable.value === true) {
|
||||
if (billableRate.value) {
|
||||
billableRateSelect.value = 'custom-rate';
|
||||
} else {
|
||||
billableRateSelect.value = 'default-rate';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
watch(billableRateSelect, () => {
|
||||
if (billableRateSelect.value === 'non-billable') {
|
||||
isBillable.value = false;
|
||||
billableRate.value = null;
|
||||
} else if (billableRateSelect.value === 'default-rate') {
|
||||
isBillable.value = true;
|
||||
billableRate.value = null;
|
||||
} else {
|
||||
isBillable.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
billableRateSelect.value = 'non-billable';
|
||||
|
||||
const billableOptionInfoTexts: { [key in BillableKey]: string } = {
|
||||
'non-billable':
|
||||
'New time entries for this project will not be marked billable by default.',
|
||||
'default-rate':
|
||||
'New time entries for this project will be billable at the default rate by default.',
|
||||
'custom-rate':
|
||||
'New time entries for this project will be billable at a custom rate by default.',
|
||||
};
|
||||
|
||||
const billableOptionInfoText = computed(() => {
|
||||
return billableOptionInfoTexts[billableRateSelect.value];
|
||||
});
|
||||
const emit = defineEmits(['submit']);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="sm:flex items-center space-y-2 sm:space-y-0 sm:space-x-4 pt-6">
|
||||
<div>
|
||||
<InputLabel for="billable" value="Billable Default" />
|
||||
<ProjectBillableSelect
|
||||
v-model="billableRateSelect"
|
||||
class="mt-2"></ProjectBillableSelect>
|
||||
</div>
|
||||
<div
|
||||
class="sm:max-w-[120px]"
|
||||
v-if="billableRateSelect === 'custom-rate'">
|
||||
<InputLabel for="billableRate" value="Billable Rate" />
|
||||
<BillableRateInput
|
||||
@keydown.enter="emit('submit')"
|
||||
v-model="billableRate"
|
||||
name="billableRate" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center text-muted pt-2 pl-1">
|
||||
<span>
|
||||
<span class="font-semibold"> Info: </span>
|
||||
{{ billableOptionInfoText }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,21 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import TextInput from '@/Components/TextInput.vue';
|
||||
import SecondaryButton from '@/Components/SecondaryButton.vue';
|
||||
import DialogModal from '@/Components/DialogModal.vue';
|
||||
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
|
||||
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
|
||||
import DialogModal from '@/packages/ui/src/DialogModal.vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import type { CreateClientBody, CreateProjectBody, Project } from '@/utils/api';
|
||||
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
||||
import type {
|
||||
CreateClientBody,
|
||||
CreateProjectBody,
|
||||
Project,
|
||||
} from '@/packages/api/src';
|
||||
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import { useFocus } from '@vueuse/core';
|
||||
import ClientDropdown from '@/Components/Common/Client/ClientDropdown.vue';
|
||||
import Badge from '@/Components/Common/Badge.vue';
|
||||
import ClientDropdown from '@/packages/ui/src/Client/ClientDropdown.vue';
|
||||
import Badge from '@/packages/ui/src/Badge.vue';
|
||||
import { useClientsStore } from '@/utils/useClients';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import ProjectColorSelector from '@/Components/Common/Project/ProjectColorSelector.vue';
|
||||
import ProjectEditBillableSection from '@/Components/Common/Project/ProjectEditBillableSection.vue';
|
||||
import ProjectColorSelector from '@/packages/ui/src/Project/ProjectColorSelector.vue';
|
||||
import { UserCircleIcon } from '@heroicons/vue/20/solid';
|
||||
import InputLabel from '@/Components/InputLabel.vue';
|
||||
import ProjectBillableRateModal from '@/Components/Common/Project/ProjectBillableRateModal.vue';
|
||||
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
|
||||
import ProjectBillableRateModal from '@/packages/ui/src/Project/ProjectBillableRateModal.vue';
|
||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||
import ProjectEditBillableSection from '@/packages/ui/src/Project/ProjectEditBillableSection.vue';
|
||||
|
||||
const { updateProject } = useProjectsStore();
|
||||
const { clients } = storeToRefs(useClientsStore());
|
||||
@@ -124,6 +129,7 @@ async function submitBillableRate() {
|
||||
</div>
|
||||
<ProjectEditBillableSection
|
||||
@submit="submit"
|
||||
:currency="getOrganizationCurrencyString()"
|
||||
v-model:isBillable="project.is_billable"
|
||||
v-model:billableRate="
|
||||
project.billable_rate
|
||||
@@ -143,6 +149,7 @@ async function submitBillableRate() {
|
||||
</DialogModal>
|
||||
<ProjectBillableRateModal
|
||||
v-model:show="showBillableRateModal"
|
||||
:currency="getOrganizationCurrencyString()"
|
||||
@submit="submitBillableRate"
|
||||
:new-billable-rate="project.billable_rate"
|
||||
:project-name="project.name"></ProjectBillableRateModal>
|
||||
|
||||
@@ -4,9 +4,9 @@ import {
|
||||
PencilSquareIcon,
|
||||
ArchiveBoxIcon,
|
||||
} from '@heroicons/vue/20/solid';
|
||||
import type { Project } from '@/utils/api';
|
||||
import type { Project } from '@/packages/api/src';
|
||||
import { canDeleteProjects, canUpdateProjects } from '@/utils/permissions';
|
||||
import MoreOptionsDropdown from '@/Components/MoreOptionsDropdown.vue';
|
||||
import MoreOptionsDropdown from '@/packages/ui/src/MoreOptionsDropdown.vue';
|
||||
const emit = defineEmits<{
|
||||
delete: [];
|
||||
edit: [];
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import MultiselectDropdown from '@/Components/Common/MultiselectDropdown.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import type { Project } from '@/utils/api';
|
||||
import type { Project } from '@/packages/api/src';
|
||||
|
||||
const projectsStore = useProjectsStore();
|
||||
const { projects } = storeToRefs(projectsStore);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import SecondaryButton from '@/Components/SecondaryButton.vue';
|
||||
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
|
||||
import { FolderPlusIcon } from '@heroicons/vue/24/solid';
|
||||
import { PlusIcon } from '@heroicons/vue/16/solid';
|
||||
import { ref } from 'vue';
|
||||
import ProjectCreateModal from '@/Components/Common/Project/ProjectCreateModal.vue';
|
||||
import ProjectCreateModal from '@/packages/ui/src/Project/ProjectCreateModal.vue';
|
||||
import ProjectTableHeading from '@/Components/Common/Project/ProjectTableHeading.vue';
|
||||
import ProjectTableRow from '@/Components/Common/Project/ProjectTableRow.vue';
|
||||
import { canCreateProjects } from '@/utils/permissions';
|
||||
@@ -12,10 +12,11 @@ import type {
|
||||
Project,
|
||||
Client,
|
||||
CreateClientBody,
|
||||
} from '@/utils/api';
|
||||
} from '@/packages/api/src';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import { useClientsStore } from '@/utils/useClients';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||
|
||||
defineProps<{
|
||||
projects: Project[];
|
||||
@@ -40,6 +41,7 @@ const { clients } = storeToRefs(useClientsStore());
|
||||
<ProjectCreateModal
|
||||
:createProject
|
||||
:createClient
|
||||
:currency="getOrganizationCurrencyString()"
|
||||
:clients="clients"
|
||||
v-model:show="showCreateProjectModal"></ProjectCreateModal>
|
||||
<div class="flow-root max-w-[100vw] overflow-x-auto">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import ProjectMoreOptionsDropdown from '@/Components/Common/Project/ProjectMoreOptionsDropdown.vue';
|
||||
import type { Project } from '@/utils/api';
|
||||
import type { Project } from '@/packages/api/src';
|
||||
import { computed, ref } from 'vue';
|
||||
import { CheckCircleIcon } from '@heroicons/vue/20/solid';
|
||||
import { useClientsStore } from '@/utils/useClients';
|
||||
@@ -9,7 +9,8 @@ import { useTasksStore } from '@/utils/useTasks';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import TableRow from '@/Components/TableRow.vue';
|
||||
import ProjectEditModal from '@/Components/Common/Project/ProjectEditModal.vue';
|
||||
import { formatCents } from '@/utils/money';
|
||||
import { formatCents } from '@/packages/ui/src/utils/money';
|
||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||
|
||||
const { clients } = storeToRefs(useClientsStore());
|
||||
const { tasks } = storeToRefs(useTasksStore());
|
||||
@@ -43,7 +44,10 @@ function archiveProject() {
|
||||
const billableRateInfo = computed(() => {
|
||||
if (props.project.is_billable) {
|
||||
if (props.project.billable_rate) {
|
||||
return formatCents(props.project.billable_rate);
|
||||
return formatCents(
|
||||
props.project.billable_rate,
|
||||
getOrganizationCurrencyString()
|
||||
);
|
||||
} else {
|
||||
return 'Default Rate';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user