move ui and api to seperate packages and add npm actions for them

This commit is contained in:
Gregor Vostrak
2024-08-21 14:28:31 +02:00
parent b7c9aa6f28
commit 635954f81d
185 changed files with 2755 additions and 712 deletions

View File

@@ -1,10 +1,10 @@
<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 { ref } from 'vue';
import type { CreateClientBody } from '@/utils/api';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import type { CreateClientBody } from '@/packages/api/src';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { useFocus } from '@vueuse/core';
import { useClientsStore } from '@/utils/useClients';

View File

@@ -1,10 +1,10 @@
<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 { ref } from 'vue';
import type { Client, UpdateClientBody } from '@/utils/api';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import type { Client, UpdateClientBody } from '@/packages/api/src';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { useFocus } from '@vueuse/core';
import { useClientsStore } from '@/utils/useClients';

View File

@@ -1,8 +1,8 @@
<script setup lang="ts">
import { PencilSquareIcon, TrashIcon } from '@heroicons/vue/20/solid';
import type { Client } from '@/utils/api';
import type { Client } from '@/packages/api/src';
import { canDeleteClients, canUpdateClients } from '@/utils/permissions';
import MoreOptionsDropdown from '@/Components/MoreOptionsDropdown.vue';
import MoreOptionsDropdown from '@/packages/ui/src/MoreOptionsDropdown.vue';
const emit = defineEmits<{
delete: [];

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import MultiselectDropdown from '@/Components/Common/MultiselectDropdown.vue';
import { storeToRefs } from 'pinia';
import type { Client } from '@/utils/api';
import type { Client } from '@/packages/api/src';
import { useClientsStore } from '@/utils/useClients';
const clientsStore = useClientsStore();

View File

@@ -1,8 +1,8 @@
<script setup lang="ts">
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import { UserCircleIcon } from '@heroicons/vue/24/solid';
import { PlusIcon } from '@heroicons/vue/16/solid';
import { ref } from 'vue';
import { type Component, ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useClientsStore } from '@/utils/useClients';
import ClientTableRow from '@/Components/Common/Client/ClientTableRow.vue';
@@ -36,7 +36,7 @@ const createClient = ref(false);
<SecondaryButton
v-if="canCreateClients()"
@click="createClient = true"
:icon="PlusIcon"
:icon="PlusIcon as Component"
>Create your First Client
</SecondaryButton>
</div>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { Client } from '@/utils/api';
import type { Client } from '@/packages/api/src';
import { computed, ref } from 'vue';
import { CheckCircleIcon } from '@heroicons/vue/20/solid';
import { useClientsStore } from '@/utils/useClients';

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { TrashIcon, ArrowPathIcon } from '@heroicons/vue/20/solid';
import MoreOptionsDropdown from '@/Components/MoreOptionsDropdown.vue';
import MoreOptionsDropdown from '@/packages/ui/src/MoreOptionsDropdown.vue';
const emit = defineEmits<{
delete: [];
resend: [];

View File

@@ -1,9 +1,9 @@
<script setup lang="ts">
import type { Invitation } from '@/utils/api';
import type { Invitation } from '@/packages/api/src';
import TableRow from '@/Components/TableRow.vue';
import { capitalizeFirstLetter } from '../../../utils/format';
import InvitationMoreOptionsDropdown from '@/Components/Common/Invitation/InvitationMoreOptionsDropdown.vue';
import { api } from '@/utils/api';
import { api } from '@/packages/api/src';
import { getCurrentOrganizationId } from '@/utils/useUser';
import { useNotificationsStore } from '@/utils/notification';
import { useInvitationsStore } from '@/utils/useInvitations';

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import { formatCents } from '../../../utils/money';
import BillableRateModal from '@/Components/Common/BillableRateModal.vue';
import { getOrganizationCurrencyString } from '@/utils/money';
import BillableRateModal from '@/packages/ui/src/BillableRateModal.vue';
import { formatCents } from '@/packages/ui/src/utils/money';
const show = defineModel('show', { default: false });
const saving = defineModel('saving', { default: false });
@@ -25,7 +26,10 @@ defineEmits<{
The billable rate of {{ memberName }} will be updated to
<strong>{{
newBillableRate
? formatCents(newBillableRate)
? formatCents(
newBillableRate,
getOrganizationCurrencyString()
)
: ' the default rate of the organization'
}}</strong
>.

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import SelectDropdown from '@/Components/Common/SelectDropdown.vue';
import Badge from '@/Components/Common/Badge.vue';
import SelectDropdown from '@/packages/ui/src/Input/SelectDropdown.vue';
import Badge from '@/packages/ui/src/Badge.vue';
import { ChevronDownIcon } from '@heroicons/vue/20/solid';
import type { BillableKey } from '@/types/projects';

View File

@@ -1,13 +1,13 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import ClientDropdownItem from '@/Components/Common/Client/ClientDropdownItem.vue';
import ClientDropdownItem from '@/packages/ui/src/Client/ClientDropdownItem.vue';
import { useMembersStore } from '@/utils/useMembers';
import { UserIcon, XMarkIcon } from '@heroicons/vue/24/solid';
import TextInput from '@/Components/TextInput.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
import { useFocus } from '@vueuse/core';
import type { ProjectMember } from '@/utils/api';
import Dropdown from '@/Components/Dropdown.vue';
import type { ProjectMember } from '@/packages/api/src';
import Dropdown from '@/packages/ui/src/Input/Dropdown.vue';
const membersStore = useMembersStore();
const { members } = storeToRefs(membersStore);

View File

@@ -1,17 +1,18 @@
<script setup lang="ts">
import SecondaryButton from '@/Components/SecondaryButton.vue';
import DialogModal from '@/Components/DialogModal.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 { Member, UpdateMemberBody } from '@/utils/api';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import type { Member, UpdateMemberBody } from '@/packages/api/src';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { type MemberBillableKey, useMembersStore } from '@/utils/useMembers';
import BillableRateInput from '@/Components/Common/BillableRateInput.vue';
import InputLabel from '@/Components/InputLabel.vue';
import BillableRateInput from '@/packages/ui/src/Input/BillableRateInput.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import MemberBillableRateModal from '@/Components/Common/Member/MemberBillableRateModal.vue';
import MemberBillableSelect from '@/Components/Common/Member/MemberBillableSelect.vue';
import { onMounted, watch } from 'vue';
import MemberRoleSelect from '@/Components/Common/Member/MemberRoleSelect.vue';
import MemberOwnershipTransferConfirmModal from '@/Components/Common/Member/MemberOwnershipTransferConfirmModal.vue';
import { getOrganizationCurrencyString } from '@/utils/money';
const { updateMember } = useMembersStore();
const show = defineModel('show', { default: false });
@@ -154,6 +155,7 @@ const roleDescription = computed(() => {
<BillableRateInput
focus
class="w-full"
:currency="getOrganizationCurrencyString()"
@keydown.enter="saveWithChecks()"
name="memberBillableRate"
v-model="

View File

@@ -1,12 +1,12 @@
<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 { ref } from 'vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { useFocus } from '@vueuse/core';
import InputLabel from '@/Components/InputLabel.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import type { Role } from '@/types/jetstream';
import { Link, useForm } from '@inertiajs/vue3';
import { getCurrentOrganizationId } from '@/utils/useUser';
@@ -14,8 +14,8 @@ import { filterRoles } from '@/utils/roles';
import { hasActiveSubscription, isBillingActivated } from '@/utils/billing';
import { CreditCardIcon, UserGroupIcon } from '@heroicons/vue/20/solid';
import { canUpdateOrganization } from '@/utils/permissions';
import { api } from '@/utils/api';
import type { MemberRole } from '@/utils/api';
import { api } from '@/packages/api/src';
import type { MemberRole } from '@/packages/api/src';
import { z } from 'zod';
import { useNotificationsStore } from '@/utils/notification';

View File

@@ -1,8 +1,8 @@
<script setup lang="ts">
import { TrashIcon, PencilSquareIcon } from '@heroicons/vue/20/solid';
import type { Member } from '@/utils/api';
import type { Member } from '@/packages/api/src';
import { canDeleteMembers, canUpdateMembers } from '@/utils/permissions';
import MoreOptionsDropdown from '@/Components/MoreOptionsDropdown.vue';
import MoreOptionsDropdown from '@/packages/ui/src/MoreOptionsDropdown.vue';
const emit = defineEmits<{
delete: [];

View File

@@ -2,7 +2,7 @@
import MultiselectDropdown from '@/Components/Common/MultiselectDropdown.vue';
import { useMembersStore } from '@/utils/useMembers';
import { storeToRefs } from 'pinia';
import type { Member } from '@/utils/api';
import type { Member } from '@/packages/api/src';
const membersStore = useMembersStore();
const { members } = storeToRefs(membersStore);

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import SecondaryButton from '@/Components/SecondaryButton.vue';
import DialogModal from '@/Components/DialogModal.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import DialogModal from '@/packages/ui/src/DialogModal.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
const show = defineModel('show', { default: false });
const saving = defineModel('saving', { default: false });

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import SelectDropdown from '@/Components/Common/SelectDropdown.vue';
import Badge from '@/Components/Common/Badge.vue';
import SelectDropdown from '@/packages/ui/src/Input/SelectDropdown.vue';
import Badge from '@/packages/ui/src/Badge.vue';
import { ChevronDownIcon } from '@heroicons/vue/20/solid';
import type { Role } from '@/types/jetstream';
import { usePage } from '@inertiajs/vue3';

View File

@@ -1,18 +1,19 @@
<script setup lang="ts">
import type { Member } from '@/utils/api';
import type { Member } from '@/packages/api/src';
import { CheckCircleIcon, UserCircleIcon } from '@heroicons/vue/20/solid';
import MemberMoreOptionsDropdown from '@/Components/Common/Member/MemberMoreOptionsDropdown.vue';
import TableRow from '@/Components/TableRow.vue';
import { capitalizeFirstLetter } from '../../../utils/format';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import { api } from '@/utils/api';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import { api } from '@/packages/api/src';
import { getCurrentOrganizationId } from '@/utils/useUser';
import { useNotificationsStore } from '@/utils/notification';
import { canInvitePlaceholderMembers } from '@/utils/permissions';
import { useMembersStore } from '@/utils/useMembers';
import { ref } from 'vue';
import MemberEditModal from '@/Components/Common/Member/MemberEditModal.vue';
import { formatCents } from '../../../utils/money';
import { getOrganizationCurrencyString } from '@/utils/money';
import { formatCents } from '@/packages/ui/src/utils/money';
const props = defineProps<{
member: Member;
@@ -62,7 +63,12 @@ async function invitePlaceholder(id: string) {
</div>
<div class="whitespace-nowrap px-3 py-4 text-sm text-muted">
{{
member.billable_rate ? formatCents(member.billable_rate) : '--'
member.billable_rate
? formatCents(
member.billable_rate,
getOrganizationCurrencyString()
)
: '--'
}}
</div>
<div

View File

@@ -1,5 +1,5 @@
<script setup lang="ts" generic="T">
import Dropdown from '@/Components/Dropdown.vue';
import Dropdown from '@/packages/ui/src/Input/Dropdown.vue';
import { type Component, computed, nextTick, ref, watch } from 'vue';
import MultiselectDropdownItem from '@/Components/Common/MultiselectDropdownItem.vue';

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import { formatCents } from '../../../utils/money';
import BillableRateModal from '@/Components/Common/BillableRateModal.vue';
import { getOrganizationCurrencyString } from '@/utils/money';
import BillableRateModal from '@/packages/ui/src/BillableRateModal.vue';
import { formatCents } from '@/packages/ui/src/utils/money';
const show = defineModel('show', { default: false });
const saving = defineModel('saving', { default: false });
@@ -23,7 +24,12 @@ defineEmits<{
<p class="py-0.5 text-center">
The organization billable rate will be updated to
<strong>{{
newBillableRate ? formatCents(newBillableRate) : ' none.'
newBillableRate
? formatCents(
newBillableRate,
getOrganizationCurrencyString()
)
: ' none.'
}}</strong
>.
</p>

View File

@@ -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);

View File

@@ -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>

View File

@@ -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: [];

View File

@@ -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);

View File

@@ -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">

View File

@@ -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';
}

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import { formatCents } from '../../../utils/money';
import BillableRateModal from '@/Components/Common/BillableRateModal.vue';
import { getOrganizationCurrencyString } from '@/utils/money';
import BillableRateModal from '@/packages/ui/src/BillableRateModal.vue';
import { formatCents } from '@/packages/ui/src/utils/money';
const show = defineModel('show', { default: false });
const saving = defineModel('saving', { default: false });
@@ -25,7 +26,10 @@ defineEmits<{
The billable rate of {{ memberName }} will be updated to
<strong>{{
newBillableRate
? formatCents(newBillableRate)
? formatCents(
newBillableRate,
getOrganizationCurrencyString()
)
: ' the default rate of the project'
}}</strong
>.

View File

@@ -1,13 +1,17 @@
<script setup lang="ts">
import SecondaryButton from '@/Components/SecondaryButton.vue';
import DialogModal from '@/Components/DialogModal.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import DialogModal from '@/packages/ui/src/DialogModal.vue';
import { ref } from 'vue';
import type { CreateProjectMemberBody, ProjectMember } from '@/utils/api';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import type {
CreateProjectMemberBody,
ProjectMember,
} from '@/packages/api/src';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { useFocus } from '@vueuse/core';
import { useProjectMembersStore } from '@/utils/useProjectMembers';
import MemberCombobox from '@/Components/Common/Member/MemberCombobox.vue';
import BillableRateInput from '@/Components/Common/BillableRateInput.vue';
import BillableRateInput from '@/packages/ui/src/Input/BillableRateInput.vue';
import { getOrganizationCurrencyString } from '@/utils/money';
const { createProjectMember } = useProjectMembersStore();
const show = defineModel('show', { default: false });
const saving = ref(false);
@@ -54,6 +58,7 @@ useFocus(projectNameInput, { initialValue: true });
<div class="col-span-3 sm:col-span-1 flex-1">
<BillableRateInput
name="billable_rate"
:currency="getOrganizationCurrencyString()"
v-model="
projectMember.billable_rate
"></BillableRateInput>

View File

@@ -1,15 +1,19 @@
<script setup lang="ts">
import SecondaryButton from '@/Components/SecondaryButton.vue';
import DialogModal from '@/Components/DialogModal.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import DialogModal from '@/packages/ui/src/DialogModal.vue';
import { ref, watch } from 'vue';
import type { ProjectMember, UpdateProjectMemberBody } from '@/utils/api';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import type {
ProjectMember,
UpdateProjectMemberBody,
} from '@/packages/api/src';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { useFocus } from '@vueuse/core';
import { useProjectMembersStore } from '@/utils/useProjectMembers';
import BillableRateInput from '@/Components/Common/BillableRateInput.vue';
import BillableRateInput from '@/packages/ui/src/Input/BillableRateInput.vue';
import { UserIcon } from '@heroicons/vue/24/solid';
import ProjectMemberBillableRateModal from '@/Components/Common/ProjectMember/ProjectMemberBillableRateModal.vue';
import InputLabel from '@/Components/InputLabel.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import { getOrganizationCurrencyString } from '@/utils/money';
const { updateProjectMember } = useProjectMembersStore();
const show = defineModel('show', { default: false });
@@ -87,6 +91,7 @@ useFocus(projectNameInput, { initialValue: true });
value="Billable Rate"></InputLabel>
<BillableRateInput
@keydown.enter="submit"
:currency="getOrganizationCurrencyString()"
name="billable_rate"
v-model="
projectMemberBody.billable_rate

View File

@@ -1,10 +1,10 @@
<script setup lang="ts">
import { TrashIcon, PencilSquareIcon } from '@heroicons/vue/20/solid';
import type { ProjectMember } from '@/utils/api';
import type { ProjectMember } from '@/packages/api/src';
import { useMembersStore } from '@/utils/useMembers';
import { storeToRefs } from 'pinia';
import { computed } from 'vue';
import MoreOptionsDropdown from '@/Components/MoreOptionsDropdown.vue';
import MoreOptionsDropdown from '@/packages/ui/src/MoreOptionsDropdown.vue';
const emit = defineEmits<{
delete: [];

View File

@@ -1,12 +1,12 @@
<script setup lang="ts">
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import { PlusIcon } from '@heroicons/vue/16/solid';
import { ref } from 'vue';
import ProjectMemberTableRow from '@/Components/Common/ProjectMember/ProjectMemberTableRow.vue';
import { UserGroupIcon } from '@heroicons/vue/24/solid';
import ProjectMemberTableHeading from '@/Components/Common/ProjectMember/ProjectMemberTableHeading.vue';
import ProjectMemberCreateModal from '@/Components/Common/ProjectMember/ProjectMemberCreateModal.vue';
import type { ProjectMember } from '@/utils/api';
import type { ProjectMember } from '@/packages/api/src';
defineProps<{
projectId: string;

View File

@@ -1,14 +1,15 @@
<script setup lang="ts">
import type { ProjectMember } from '@/utils/api';
import type { ProjectMember } from '@/packages/api/src';
import { computed, ref } from 'vue';
import { storeToRefs } from 'pinia';
import TableRow from '@/Components/TableRow.vue';
import { useMembersStore } from '@/utils/useMembers';
import { useProjectMembersStore } from '@/utils/useProjectMembers';
import ProjectMemberMoreOptionsDropdown from '@/Components/Common/ProjectMember/ProjectMemberMoreOptionsDropdown.vue';
import { formatCents } from '@/utils/money';
import { formatCents } from '@/packages/ui/src/utils/money';
import { capitalizeFirstLetter } from '@/utils/format';
import ProjectMemberEditModal from '@/Components/Common/ProjectMember/ProjectMemberEditModal.vue';
import { getOrganizationCurrencyString } from '@/utils/money';
const props = defineProps<{
projectMember: ProjectMember;
@@ -48,7 +49,10 @@ const showEditModal = ref(false);
<div class="whitespace-nowrap px-3 py-4 text-sm text-muted">
{{
projectMember.billable_rate
? formatCents(projectMember.billable_rate)
? formatCents(
projectMember.billable_rate,
getOrganizationCurrencyString()
)
: '--'
}}
</div>

View File

@@ -6,7 +6,7 @@ import {
formatDate,
formatHumanReadableDuration,
formatWeek,
} from '@/utils/time';
} from '@/packages/ui/src/utils/time';
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { BarChart } from 'echarts/charts';
@@ -16,7 +16,7 @@ import {
TitleComponent,
TooltipComponent,
} from 'echarts/components';
import type { AggregatedTimeEntries } from '@/utils/api';
import type { AggregatedTimeEntries } from '@/packages/api/src';
import { useCssVar } from '@vueuse/core';
use([

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import Badge from '@/Components/Common/Badge.vue';
import Badge from '@/packages/ui/src/Badge.vue';
const props = defineProps<{
icon: Component;

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import SelectDropdown from '@/Components/Common/SelectDropdown.vue';
import Badge from '@/Components/Common/Badge.vue';
import SelectDropdown from '@/packages/ui/src/Input/SelectDropdown.vue';
import Badge from '@/packages/ui/src/Badge.vue';
import { type Component, computed } from 'vue';
const model = defineModel<string | null>({ default: null });

View File

@@ -11,9 +11,9 @@ import {
TitleComponent,
TooltipComponent,
} from 'echarts/components';
import { formatHumanReadableDuration } from '@/utils/time';
import { getRandomColorWithSeed } from '@/utils/color';
import type { GroupedDataEntries } from '@/utils/api';
import { formatHumanReadableDuration } from '@/packages/ui/src/utils/time';
import { getRandomColorWithSeed } from '@/packages/ui/src/utils/color';
import type { GroupedDataEntries } from '@/packages/api/src';
import { useReportingStore } from '@/utils/useReporting';
use([

View File

@@ -1,10 +1,11 @@
<script setup lang="ts">
import { formatHumanReadableDuration } from '@/utils/time';
import { formatCents } from '@/utils/money';
import GroupedItemsCountButton from '@/Components/Common/GroupedItemsCountButton.vue';
import { formatHumanReadableDuration } from '@/packages/ui/src/utils/time';
import { formatCents } from '@/packages/ui/src/utils/money';
import GroupedItemsCountButton from '@/packages/ui/src/GroupedItemsCountButton.vue';
import { ref } from 'vue';
import { twMerge } from 'tailwind-merge';
import { useReportingStore } from '@/utils/useReporting';
import { getOrganizationCurrencyString } from '@/utils/money';
const { getNameForReportingRowEntry } = useReportingStore();
type AggregatedGroupedData = GroupedData & {
@@ -54,7 +55,7 @@ const expanded = ref(false);
{{ formatHumanReadableDuration(entry.seconds) }}
</div>
<div class="justify-end pr-6 flex items-center">
{{ formatCents(entry.cost) }}
{{ formatCents(entry.cost, getOrganizationCurrencyString()) }}
</div>
</div>
<div

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { TrashIcon } from '@heroicons/vue/20/solid';
import type { Tag } from '@/utils/api';
import MoreOptionsDropdown from '@/Components/MoreOptionsDropdown.vue';
import type { Tag } from '@/packages/api/src';
import MoreOptionsDropdown from '@/packages/ui/src/MoreOptionsDropdown.vue';
const emit = defineEmits<{
delete: [];

View File

@@ -1,15 +1,15 @@
<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 { storeToRefs } from 'pinia';
import { useTagsStore } from '@/utils/useTags';
import TagTableRow from '@/Components/Common/Tag/TagTableRow.vue';
import TagCreateModal from '@/Components/Common/Tag/TagCreateModal.vue';
import TagCreateModal from '@/packages/ui/src/Tag/TagCreateModal.vue';
import TagTableHeading from '@/Components/Common/Tag/TagTableHeading.vue';
import { canCreateTags } from '@/utils/permissions';
import type { Tag } from '@/utils/api';
import type { Tag } from '@/packages/api/src';
defineProps<{
createTag: (name: string) => Promise<Tag | undefined>;
}>();

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { Tag } from '@/utils/api';
import type { Tag } from '@/packages/api/src';
import { useTagsStore } from '@/utils/useTags';
import TagMoreOptionsDropdown from '@/Components/Common/Tag/TagMoreOptionsDropdown.vue';
import TableRow from '@/Components/TableRow.vue';

View File

@@ -1,9 +1,9 @@
<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 { ref } from 'vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { useFocus } from '@vueuse/core';
import { useTasksStore } from '@/utils/useTasks';
import ProjectDropdown from '@/Components/Common/Project/ProjectDropdown.vue';

View File

@@ -1,12 +1,12 @@
<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 { ref } from 'vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { useFocus } from '@vueuse/core';
import { useTasksStore } from '@/utils/useTasks';
import type { Task, UpdateTaskBody } from '@/utils/api';
import type { Task, UpdateTaskBody } from '@/packages/api/src';
const { updateTask } = useTasksStore();
const show = defineModel('show', { default: false });

View File

@@ -4,9 +4,9 @@ import {
PencilSquareIcon,
CheckCircleIcon,
} from '@heroicons/vue/20/solid';
import type { Task } from '@/utils/api';
import type { Task } from '@/packages/api/src';
import { canDeleteTasks, canUpdateTasks } from '@/utils/permissions';
import MoreOptionsDropdown from '@/Components/MoreOptionsDropdown.vue';
import MoreOptionsDropdown from '@/packages/ui/src/MoreOptionsDropdown.vue';
const emit = defineEmits<{
delete: [];
edit: [];

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import MultiselectDropdown from '@/Components/Common/MultiselectDropdown.vue';
import { storeToRefs } from 'pinia';
import type { Task } from '@/utils/api';
import type { Task } from '@/packages/api/src';
import { useTasksStore } from '@/utils/useTasks';
const tasksStore = useTasksStore();

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import { PlusCircleIcon } from '@heroicons/vue/24/solid';
import { PlusIcon } from '@heroicons/vue/16/solid';
import { ref } from 'vue';
@@ -7,7 +7,7 @@ import TaskTableRow from '@/Components/Common/Task/TaskTableRow.vue';
import TaskTableHeading from '@/Components/Common/Task/TaskTableHeading.vue';
import TaskCreateModal from '@/Components/Common/Task/TaskCreateModal.vue';
import { canCreateTasks } from '@/utils/permissions';
import type { Task } from '@/utils/api';
import type { Task } from '@/packages/api/src';
const props = defineProps<{
projectId: string;

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { Task } from '@/utils/api';
import type { Task } from '@/packages/api/src';
import { CheckCircleIcon } from '@heroicons/vue/20/solid';
import { useTasksStore } from '@/utils/useTasks';
import TaskMoreOptionsDropdown from '@/Components/Common/Task/TaskMoreOptionsDropdown.vue';

View File

@@ -1,18 +1,20 @@
<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 { nextTick, ref, watch } from 'vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TimeTrackerTagDropdown from '@/Components/Common/TimeTracker/TimeTrackerTagDropdown.vue';
import TimeTrackerProjectTaskDropdown from '@/Components/Common/TimeTracker/TimeTrackerProjectTaskDropdown.vue';
import BillableToggleButton from '@/Components/Common/BillableToggleButton.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import TimeTrackerTagDropdown from '@/packages/ui/src/TimeTracker/TimeTrackerTagDropdown.vue';
import TimeTrackerProjectTaskDropdown from '@/packages/ui/src/TimeTracker/TimeTrackerProjectTaskDropdown.vue';
import BillableToggleButton from '@/packages/ui/src/Input/BillableToggleButton.vue';
import { getCurrentUserId } from '@/utils/useUser';
import { useTimeEntriesStore } from '@/utils/useTimeEntries';
import InputLabel from '@/Components/InputLabel.vue';
import TimePicker from '@/Components/Common/TimePicker.vue';
import DatePicker from '@/Components/Common/DatePicker.vue';
import { getDayJsInstance, getLocalizedDayJs } from '@/utils/time';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import DatePicker from '@/packages/ui/src/Input/DatePicker.vue';
import {
getDayJsInstance,
getLocalizedDayJs,
} from '@/packages/ui/src/utils/time';
import { storeToRefs } from 'pinia';
import { useTasksStore } from '@/utils/useTasks';
import { useProjectsStore } from '@/utils/useProjects';
@@ -22,8 +24,10 @@ import type {
CreateProjectBody,
Project,
Client,
} from '@/utils/api';
} from '@/packages/api/src';
import { useClientsStore } from '@/utils/useClients';
import TimePicker from '@/packages/ui/src/Input/TimePicker.vue';
import { getOrganizationCurrencyString } from '@/utils/money';
const projectStore = useProjectsStore();
const { projects } = storeToRefs(projectStore);
const taskStore = useTasksStore();
@@ -126,6 +130,7 @@ async function createTag(tag: string) {
:clients
:createProject
:createClient
:currency="getOrganizationCurrencyString()"
class="mt-1"
size="xlarge"
:projects="projects"

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import Modal from './Modal.vue';
import Modal from '@/packages/ui/src/Modal.vue';
const emit = defineEmits(['close']);

View File

@@ -1,10 +1,10 @@
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue';
import DialogModal from './DialogModal.vue';
import InputError from './InputError.vue';
import PrimaryButton from './PrimaryButton.vue';
import SecondaryButton from './SecondaryButton.vue';
import TextInput from './TextInput.vue';
import DialogModal from '@/packages/ui/src/DialogModal.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
import axios from 'axios';
const emit = defineEmits(['confirmed']);

View File

@@ -3,8 +3,8 @@ import { useCurrentTimeEntryStore } from '@/utils/useCurrentTimeEntry';
import { storeToRefs } from 'pinia';
import { computed } from 'vue';
import dayjs from 'dayjs';
import { formatHumanReadableDuration } from '@/utils/time';
import TimeTrackerStartStop from '@/Components/Common/TimeTrackerStartStop.vue';
import { formatHumanReadableDuration } from '@/packages/ui/src/utils/time';
import TimeTrackerStartStop from '@/packages/ui/src/TimeTrackerStartStop.vue';
import { getCurrentOrganizationId } from '@/utils/useUser';
const store = useCurrentTimeEntryStore();
const { currentTimeEntry, now, isActive } = storeToRefs(store);

View File

@@ -18,7 +18,7 @@ import {
formatDate,
formatHumanReadableDuration,
getDayJsInstance,
} from '@/utils/time';
} from '@/packages/ui/src/utils/time';
import { useCssVar } from '@vueuse/core';
const props = defineProps<{

View File

@@ -12,7 +12,7 @@
<script setup lang="ts">
import type { Component } from 'vue';
import CardTitle from '@/Components/Common/CardTitle.vue';
import CardTitle from '@/packages/ui/src/CardTitle.vue';
defineProps<{
title: string;

View File

@@ -9,7 +9,7 @@ defineProps<{
import {
formatHumanReadableDate,
formatHumanReadableDuration,
} from '@/utils/time';
} from '@/packages/ui/src/utils/time';
</script>
<template>

View File

@@ -11,7 +11,7 @@ import {
TitleComponent,
TooltipComponent,
} from 'echarts/components';
import { formatHumanReadableDuration } from '@/utils/time';
import { formatHumanReadableDuration } from '@/packages/ui/src/utils/time';
use([
CanvasRenderer,

View File

@@ -2,7 +2,7 @@
import RecentlyTrackedTasksCardEntry from '@/Components/Dashboard/RecentlyTrackedTasksCardEntry.vue';
import DashboardCard from '@/Components/Dashboard/DashboardCard.vue';
import { CheckCircleIcon } from '@heroicons/vue/20/solid';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import { PlusCircleIcon } from '@heroicons/vue/24/solid';
import { router } from '@inertiajs/vue3';

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import ProjectBadge from '@/Components/Common/Project/ProjectBadge.vue';
import TimeTrackerStartStop from '@/Components/Common/TimeTrackerStartStop.vue';
import ProjectBadge from '@/packages/ui/src/Project/ProjectBadge.vue';
import TimeTrackerStartStop from '@/packages/ui/src/TimeTrackerStartStop.vue';
import { useProjectsStore } from '@/utils/useProjects';
import { storeToRefs } from 'pinia';
import { computed } from 'vue';

View File

@@ -3,7 +3,7 @@ import DashboardCard from '@/Components/Dashboard/DashboardCard.vue';
import TeamActivityCardEntry from '@/Components/Dashboard/TeamActivityCardEntry.vue';
import { UserGroupIcon } from '@heroicons/vue/20/solid';
import { router } from '@inertiajs/vue3';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
defineProps<{
latestTeamActivity: {

View File

@@ -12,13 +12,14 @@ import VChart, { THEME_KEY } from 'vue-echarts';
import { computed, provide, ref } from 'vue';
import StatCard from '@/Components/Common/StatCard.vue';
import { ClockIcon } from '@heroicons/vue/20/solid';
import CardTitle from '@/Components/Common/CardTitle.vue';
import CardTitle from '@/packages/ui/src/CardTitle.vue';
import LinearGradient from 'zrender/lib/graphic/LinearGradient';
import ProjectsChartCard from '@/Components/Dashboard/ProjectsChartCard.vue';
import { formatHumanReadableDuration } from '@/utils/time';
import { formatCents } from '@/utils/money';
import { formatHumanReadableDuration } from '@/packages/ui/src/utils/time';
import { formatCents } from '@/packages/ui/src/utils/money';
import { getWeekStart } from '@/utils/useUser';
import { useCssVar } from '@vueuse/core';
import { getOrganizationCurrencyString } from '@/utils/money';
use([
CanvasRenderer,
@@ -195,7 +196,12 @@ const option = ref({
" />
<StatCard
title="Billable Amount"
:value="formatCents(props.totalWeeklyBillableAmount.value)" />
:value="
formatCents(
props.totalWeeklyBillableAmount.value,
getOrganizationCurrencyString()
)
" />
<ProjectsChartCard
:weekly-project-overview="
props.weeklyProjectOverview

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ChevronDownIcon } from '@heroicons/vue/20/solid';
import Dropdown from '@/Components/Dropdown.vue';
import Dropdown from '@/packages/ui/src/Input/Dropdown.vue';
import DropdownLink from '@/Components/DropdownLink.vue';
import { usePage } from '@inertiajs/vue3';
import type { Organization, User } from '@/types/models';

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ClockIcon } from '@heroicons/vue/20/solid';
import CardTitle from '@/Components/Common/CardTitle.vue';
import CardTitle from '@/packages/ui/src/CardTitle.vue';
import { usePage } from '@inertiajs/vue3';
import { type User } from '@/types/models';
import { computed, onMounted, watch } from 'vue';
@@ -15,10 +15,15 @@ import { switchOrganization } from '@/utils/useOrganization';
import { useProjectsStore } from '@/utils/useProjects';
import { useTasksStore } from '@/utils/useTasks';
import { useTagsStore } from '@/utils/useTags';
import TimeTrackerControls from '@/Components/Common/TimeTracker/TimeTrackerControls.vue';
import type { CreateClientBody, CreateProjectBody, Project } from '@/utils/api';
import TimeTrackerRunningInDifferentOrganizationOverlay from '@/Components/Common/TimeTracker/TimeTrackerRunningInDifferentOrganizationOverlay.vue';
import TimeTrackerControls from '@/packages/ui/src/TimeTracker/TimeTrackerControls.vue';
import type {
CreateClientBody,
CreateProjectBody,
Project,
} from '@/packages/api/src';
import TimeTrackerRunningInDifferentOrganizationOverlay from '@/packages/ui/src/TimeTracker/TimeTrackerRunningInDifferentOrganizationOverlay.vue';
import { useClientsStore } from '@/utils/useClients';
import { getOrganizationCurrencyString } from '@/utils/money';
const page = usePage<{
auth: {
@@ -108,6 +113,7 @@ const { tags } = storeToRefs(useTagsStore());
:projects
:createTag
:isActive
:currency="getOrganizationCurrencyString()"
v-model:currentTimeEntry="currentTimeEntry"
v-model:liveTimer="now"
@startLiveTimer="startLiveTimer"

View File

@@ -2,7 +2,7 @@
import { router, usePage } from '@inertiajs/vue3';
import type { Organization, User } from '@/types/models';
import DropdownLink from '@/Components/DropdownLink.vue';
import Dropdown from '@/Components/Dropdown.vue';
import Dropdown from '@/packages/ui/src/Input/Dropdown.vue';
const page = usePage<{
jetstream: {

View File

@@ -32,7 +32,7 @@ import {
import { isBillingActivated } from '@/utils/billing';
import type { User } from '@/types/models';
import { ArrowsRightLeftIcon } from '@heroicons/vue/16/solid';
import { fetchToken, isTokenValid } from '@/utils/api';
import { fetchToken, isTokenValid } from '@/utils/session';
defineProps({
title: String,

View File

@@ -3,17 +3,17 @@ import { ref } from 'vue';
import { useForm, usePage } from '@inertiajs/vue3';
import ActionMessage from '@/Components/ActionMessage.vue';
import ActionSection from '@/Components/ActionSection.vue';
import Checkbox from '@/Components/Checkbox.vue';
import Checkbox from '@/packages/ui/src/Input/Checkbox.vue';
import ConfirmationModal from '@/Components/ConfirmationModal.vue';
import DangerButton from '@/Components/DangerButton.vue';
import DialogModal from '@/Components/DialogModal.vue';
import DangerButton from '@/packages/ui/src/Buttons/DangerButton.vue';
import DialogModal from '@/packages/ui/src/DialogModal.vue';
import FormSection from '@/Components/FormSection.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import SectionBorder from '@/Components/SectionBorder.vue';
import TextInput from '@/Components/TextInput.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
import type { Token } from '@/types/jetstream';
const props = defineProps<{

View File

@@ -3,10 +3,10 @@ import { ref } from 'vue';
import { Head, useForm } from '@inertiajs/vue3';
import AuthenticationCard from '@/Components/AuthenticationCard.vue';
import AuthenticationCardLogo from '@/Components/AuthenticationCardLogo.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
const form = useForm({
password: '',

View File

@@ -2,10 +2,10 @@
import { Head, useForm } from '@inertiajs/vue3';
import AuthenticationCard from '@/Components/AuthenticationCard.vue';
import AuthenticationCardLogo from '@/Components/AuthenticationCardLogo.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
defineProps({
status: String,

View File

@@ -2,10 +2,10 @@
import { Head, Link, useForm, usePage } from '@inertiajs/vue3';
import AuthenticationCard from '@/Components/AuthenticationCard.vue';
import AuthenticationCardLogo from '@/Components/AuthenticationCardLogo.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
defineProps({
canResetPassword: Boolean,

View File

@@ -2,11 +2,11 @@
import { Head, Link, useForm, usePage } from '@inertiajs/vue3';
import AuthenticationCard from '@/Components/AuthenticationCard.vue';
import AuthenticationCardLogo from '@/Components/AuthenticationCardLogo.vue';
import Checkbox from '@/Components/Checkbox.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import Checkbox from '@/packages/ui/src/Input/Checkbox.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
const form = useForm({
name: '',

View File

@@ -2,10 +2,10 @@
import { Head, useForm } from '@inertiajs/vue3';
import AuthenticationCard from '@/Components/AuthenticationCard.vue';
import AuthenticationCardLogo from '@/Components/AuthenticationCardLogo.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
const props = defineProps({
email: String,

View File

@@ -3,10 +3,10 @@ import { nextTick, ref } from 'vue';
import { Head, useForm } from '@inertiajs/vue3';
import AuthenticationCard from '@/Components/AuthenticationCard.vue';
import AuthenticationCardLogo from '@/Components/AuthenticationCardLogo.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
const recovery = ref(false);

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue';
import { Head, Link, useForm } from '@inertiajs/vue3';
import AuthenticationCard from '@/Components/AuthenticationCard.vue';
import AuthenticationCardLogo from '@/Components/AuthenticationCardLogo.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
const props = defineProps({
status: String,

View File

@@ -2,7 +2,7 @@
import MainContainer from '@/Pages/MainContainer.vue';
import AppLayout from '@/Layouts/AppLayout.vue';
import { PlusIcon } from '@heroicons/vue/16/solid';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import { UserCircleIcon } from '@heroicons/vue/20/solid';
import { onMounted, ref } from 'vue';
import { useClientsStore } from '@/utils/useClients';

View File

@@ -3,7 +3,7 @@ import MainContainer from '@/Pages/MainContainer.vue';
import AppLayout from '@/Layouts/AppLayout.vue';
import { PlusIcon } from '@heroicons/vue/16/solid';
import { UserGroupIcon } from '@heroicons/vue/20/solid';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import TabBar from '@/Components/Common/TabBar/TabBar.vue';
import TabBarItem from '@/Components/Common/TabBar/TabBarItem.vue';
import { ref } from 'vue';

View File

@@ -2,11 +2,11 @@
import { ref } from 'vue';
import { useForm } from '@inertiajs/vue3';
import ActionSection from '@/Components/ActionSection.vue';
import DangerButton from '@/Components/DangerButton.vue';
import DialogModal from '@/Components/DialogModal.vue';
import InputError from '@/Components/InputError.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import DangerButton from '@/packages/ui/src/Buttons/DangerButton.vue';
import DialogModal from '@/packages/ui/src/DialogModal.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
const confirmingUserDeletion = ref(false);
const passwordInput = ref<HTMLElement | null>(null);

View File

@@ -3,11 +3,11 @@ import { ref } from 'vue';
import { useForm } from '@inertiajs/vue3';
import ActionMessage from '@/Components/ActionMessage.vue';
import ActionSection from '@/Components/ActionSection.vue';
import DialogModal from '@/Components/DialogModal.vue';
import InputError from '@/Components/InputError.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import DialogModal from '@/packages/ui/src/DialogModal.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
import type { Session } from '@/types/jetstream';
defineProps<{

View File

@@ -3,12 +3,12 @@ import { ref, computed, watch } from 'vue';
import { router, useForm, usePage } from '@inertiajs/vue3';
import ActionSection from '@/Components/ActionSection.vue';
import ConfirmsPassword from '@/Components/ConfirmsPassword.vue';
import DangerButton from '@/Components/DangerButton.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import DangerButton from '@/packages/ui/src/Buttons/DangerButton.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
import axios from 'axios';
import type { JetstreamUser } from '@/types/jetstream';

View File

@@ -3,10 +3,10 @@ import { ref } from 'vue';
import { useForm } from '@inertiajs/vue3';
import ActionMessage from '@/Components/ActionMessage.vue';
import FormSection from '@/Components/FormSection.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
const passwordInput = ref<HTMLElement | null>(null);
const currentPasswordInput = ref<HTMLElement | null>(null);

View File

@@ -3,11 +3,11 @@ import { ref } from 'vue';
import { Link, router, useForm, usePage } from '@inertiajs/vue3';
import ActionMessage from '@/Components/ActionMessage.vue';
import FormSection from '@/Components/FormSection.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
import type { User } from '@/types/models';
const props = defineProps<{

View File

@@ -2,7 +2,7 @@
import MainContainer from '@/Pages/MainContainer.vue';
import AppLayout from '@/Layouts/AppLayout.vue';
import { FolderIcon, PlusIcon } from '@heroicons/vue/16/solid';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import { computed, onMounted, ref } from 'vue';
import { useProjectsStore } from '@/utils/useProjects';
import { storeToRefs } from 'pinia';
@@ -14,7 +14,7 @@ import {
import { Link } from '@inertiajs/vue3';
import TaskCreateModal from '@/Components/Common/Task/TaskCreateModal.vue';
import TaskTable from '@/Components/Common/Task/TaskTable.vue';
import CardTitle from '@/Components/Common/CardTitle.vue';
import CardTitle from '@/packages/ui/src/CardTitle.vue';
import Card from '@/Components/Common/Card.vue';
import ProjectMemberTable from '@/Components/Common/ProjectMember/ProjectMemberTable.vue';
import ProjectMemberCreateModal from '@/Components/Common/ProjectMember/ProjectMemberCreateModal.vue';

View File

@@ -2,11 +2,11 @@
import MainContainer from '@/Pages/MainContainer.vue';
import AppLayout from '@/Layouts/AppLayout.vue';
import { FolderIcon, PlusIcon } from '@heroicons/vue/16/solid';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import ProjectTable from '@/Components/Common/Project/ProjectTable.vue';
import { computed, onMounted, ref } from 'vue';
import { useProjectsStore } from '@/utils/useProjects';
import ProjectCreateModal from '@/Components/Common/Project/ProjectCreateModal.vue';
import ProjectCreateModal from '@/packages/ui/src/Project/ProjectCreateModal.vue';
import PageTitle from '@/Components/Common/PageTitle.vue';
import { canCreateProjects } from '@/utils/permissions';
import TabBarItem from '@/Components/Common/TabBar/TabBarItem.vue';
@@ -18,7 +18,8 @@ import type {
Client,
CreateProjectBody,
Project,
} from '@/utils/api';
} from '@/packages/api/src';
import { getOrganizationCurrencyString } from '@/utils/money';
onMounted(() => {
useProjectsStore().fetchProjects();
@@ -82,6 +83,7 @@ async function createClient(
<ProjectCreateModal
:createProject
:createClient
:currency="getOrganizationCurrencyString()"
:clients="clients"
@submit="createProject"
v-model:show="showCreateProjectModal"></ProjectCreateModal>

View File

@@ -9,31 +9,32 @@ import {
CheckCircleIcon,
TagIcon,
} from '@heroicons/vue/20/solid';
import DateRangePicker from '@/Components/Common/DateRangePicker.vue';
import DateRangePicker from '@/packages/ui/src/Input/DateRangePicker.vue';
import ReportingChart from '@/Components/Common/Reporting/ReportingChart.vue';
import BillableIcon from '@/Components/Common/Icons/BillableIcon.vue';
import BillableIcon from '@/packages/ui/src/Icons/BillableIcon.vue';
import { onMounted, ref } from 'vue';
import {
formatHumanReadableDuration,
getDayJsInstance,
getLocalizedDayJs,
} from '@/utils/time';
} from '@/packages/ui/src/utils/time';
import { type GroupingOption, useReportingStore } from '@/utils/useReporting';
import { storeToRefs } from 'pinia';
import TagDropdown from '@/Components/Common/Tag/TagDropdown.vue';
import type { AggregatedTimeEntriesQueryParams } from '@/utils/api';
import TagDropdown from '@/packages/ui/src/Tag/TagDropdown.vue';
import type { AggregatedTimeEntriesQueryParams } from '@/packages/api/src';
import ReportingFilterBadge from '@/Components/Common/Reporting/ReportingFilterBadge.vue';
import ProjectMultiselectDropdown from '@/Components/Common/Project/ProjectMultiselectDropdown.vue';
import MemberMultiselectDropdown from '@/Components/Common/Member/MemberMultiselectDropdown.vue';
import TaskMultiselectDropdown from '@/Components/Common/Task/TaskMultiselectDropdown.vue';
import SelectDropdown from '@/Components/Common/SelectDropdown.vue';
import SelectDropdown from '@/packages/ui/src/Input/SelectDropdown.vue';
import ReportingGroupBySelect from '@/Components/Common/Reporting/ReportingGroupBySelect.vue';
import ReportingRow from '@/Components/Common/Reporting/ReportingRow.vue';
import { formatCents } from '@/utils/money';
import { getOrganizationCurrencyString } from '@/utils/money';
import ReportingPieChart from '@/Components/Common/Reporting/ReportingPieChart.vue';
import { getCurrentMembershipId, getCurrentRole } from '@/utils/useUser';
import ClientMultiselectDropdown from '@/Components/Common/Client/ClientMultiselectDropdown.vue';
import { useTagsStore } from '@/utils/useTags';
import { formatCents } from '@/packages/ui/src/utils/money';
const startDate = ref<string>(
getLocalizedDayJs(getDayJsInstance()().format()).subtract(14, 'd').format()
@@ -322,7 +323,8 @@ async function createTag(tag: string) {
class="justify-end pr-6 flex items-center font-medium">
{{
formatCents(
aggregatedTableTimeEntries.cost
aggregatedTableTimeEntries.cost,
getOrganizationCurrencyString()
)
}}
</div>

View File

@@ -2,10 +2,10 @@
import MainContainer from '@/Pages/MainContainer.vue';
import AppLayout from '@/Layouts/AppLayout.vue';
import { TagIcon, PlusIcon } from '@heroicons/vue/16/solid';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import { ref } from 'vue';
import TagTable from '@/Components/Common/Tag/TagTable.vue';
import TagCreateModal from '@/Components/Common/Tag/TagCreateModal.vue';
import TagCreateModal from '@/packages/ui/src/Tag/TagCreateModal.vue';
import PageTitle from '@/Components/Common/PageTitle.vue';
import { canCreateTags } from '@/utils/permissions';
import { useTagsStore } from '@/utils/useTags';

View File

@@ -1,10 +1,10 @@
<script setup lang="ts">
import { useForm, usePage } from '@inertiajs/vue3';
import FormSection from '@/Components/FormSection.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
import type { User } from '@/types/models';
import { initializeStores } from '@/utils/init';

View File

@@ -3,8 +3,8 @@ import { ref } from 'vue';
import { useForm } from '@inertiajs/vue3';
import ActionSection from '@/Components/ActionSection.vue';
import ConfirmationModal from '@/Components/ConfirmationModal.vue';
import DangerButton from '@/Components/DangerButton.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import DangerButton from '@/packages/ui/src/Buttons/DangerButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
const props = defineProps({
team: Object,

View File

@@ -1,15 +1,15 @@
<script setup lang="ts">
import FormSection from '@/Components/FormSection.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { computed, onMounted, ref } from 'vue';
import { useNotificationsStore } from '@/utils/notification';
import { api } from '@/utils/api';
import InputLabel from '@/Components/InputLabel.vue';
import { api } from '@/packages/api/src';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import { DocumentIcon } from '@heroicons/vue/24/solid';
import { getCurrentOrganizationId } from '@/utils/useUser';
import type { ImportReport, ImportType } from '@/utils/api';
import DialogModal from '@/Components/DialogModal.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import type { ImportReport, ImportType } from '@/packages/api/src';
import DialogModal from '@/packages/ui/src/DialogModal.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import { initializeStores } from '@/utils/init';
const importTypeOptions = ref<ImportType[]>([]);

View File

@@ -1,13 +1,14 @@
<script setup lang="ts">
import FormSection from '@/Components/FormSection.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { onMounted, ref } from 'vue';
import InputLabel from '@/Components/InputLabel.vue';
import type { UpdateOrganizationBody } from '@/utils/api';
import BillableRateInput from '@/Components/Common/BillableRateInput.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import type { UpdateOrganizationBody } from '@/packages/api/src';
import BillableRateInput from '@/packages/ui/src/Input/BillableRateInput.vue';
import { useOrganizationStore } from '@/utils/useOrganization';
import { storeToRefs } from 'pinia';
import OrganizationBillableRateModal from '@/Components/Common/Organization/OrganizationBillableRateModal.vue';
import { getOrganizationCurrencyString } from '@/utils/money';
const store = useOrganizationStore();
const { fetchOrganization, updateOrganization } = store;
@@ -58,6 +59,7 @@ async function submit() {
value="Organization Billable Rate" />
<BillableRateInput
v-if="organization"
:currency="getOrganizationCurrencyString()"
v-model="organizationBody.billable_rate"
name="organizationBillableRate"></BillableRateInput>
</div>

View File

@@ -4,15 +4,15 @@ import { router, useForm, usePage } from '@inertiajs/vue3';
import ActionMessage from '@/Components/ActionMessage.vue';
import ActionSection from '@/Components/ActionSection.vue';
import ConfirmationModal from '@/Components/ConfirmationModal.vue';
import DangerButton from '@/Components/DangerButton.vue';
import DialogModal from '@/Components/DialogModal.vue';
import DangerButton from '@/packages/ui/src/Buttons/DangerButton.vue';
import DialogModal from '@/packages/ui/src/DialogModal.vue';
import FormSection from '@/Components/FormSection.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import SectionBorder from '@/Components/SectionBorder.vue';
import TextInput from '@/Components/TextInput.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
import type {
Organization,
OrganizationInvitation,

View File

@@ -2,10 +2,10 @@
import { Link, useForm } from '@inertiajs/vue3';
import ActionMessage from '@/Components/ActionMessage.vue';
import FormSection from '@/Components/FormSection.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
import type { Organization } from '@/types/models';
import type { Permissions } from '@/types/jetstream';
import { CreditCardIcon } from '@heroicons/vue/20/solid';

View File

@@ -12,19 +12,20 @@ import type {
Project,
TimeEntry,
Client,
} from '@/utils/api';
} from '@/packages/api/src';
import { useElementVisibility } from '@vueuse/core';
import { ClockIcon } from '@heroicons/vue/20/solid';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import { PlusIcon } from '@heroicons/vue/16/solid';
import TimeEntryCreateModal from '@/Components/Common/TimeEntry/TimeEntryCreateModal.vue';
import LoadingSpinner from '@/Components/LoadingSpinner.vue';
import LoadingSpinner from '@/packages/ui/src/LoadingSpinner.vue';
import { useCurrentTimeEntryStore } from '@/utils/useCurrentTimeEntry';
import { useTasksStore } from '@/utils/useTasks';
import { useProjectsStore } from '@/utils/useProjects';
import TimeEntryGroupedTable from '@/Components/Common/TimeEntry/TimeEntryGroupedTable.vue';
import TimeEntryGroupedTable from '@/packages/ui/src/TimeEntry/TimeEntryGroupedTable.vue';
import { useTagsStore } from '@/utils/useTags';
import { useClientsStore } from '@/utils/useClients';
import TimeEntryCreateModal from '@/Components/Common/TimeEntry/TimeEntryCreateModal.vue';
import { getOrganizationCurrencyString } from '@/utils/money';
const timeEntriesStore = useTimeEntriesStore();
const { timeEntries, allTimeEntriesLoaded } = storeToRefs(timeEntriesStore);
@@ -134,6 +135,7 @@ async function createClient(
:createTag
:projects="projects"
:tasks="tasks"
:currency="getOrganizationCurrencyString()"
:timeEntries="timeEntries"
:tags="tags"></TimeEntryGroupedTable>
<div v-if="timeEntries.length === 0" class="text-center pt-12">

5
resources/js/packages/api/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
node_modules
dist
out
.DS_Store
*.log*

View File

@@ -0,0 +1,171 @@
{
"name": "@solidtime/api",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@solidtime/api",
"version": "0.1.0",
"license": "AGPL-3.0",
"dependencies": {
"@zodios/core": "^10.9.6",
"typescript": "^5.5.4",
"zod": "^3.23.8"
},
"devDependencies": {
"@vercel/ncc": "^0.38.1"
}
},
"node_modules/@vercel/ncc": {
"version": "0.38.1",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.1.tgz",
"integrity": "sha512-IBBb+iI2NLu4VQn3Vwldyi2QwaXt5+hTyh58ggAMoCGE6DJmPvwL3KPBWcJl1m9LYPChBLE980Jw+CS4Wokqxw==",
"dev": true,
"license": "MIT",
"bin": {
"ncc": "dist/ncc/cli.js"
}
},
"node_modules/@zodios/core": {
"version": "10.9.6",
"resolved": "https://registry.npmjs.org/@zodios/core/-/core-10.9.6.tgz",
"integrity": "sha512-aH4rOdb3AcezN7ws8vDgBfGboZMk2JGGzEq/DtW65MhnRxyTGRuLJRWVQ/2KxDgWvV2F5oTkAS+5pnjKbl0n+A==",
"license": "MIT",
"peerDependencies": {
"axios": "^0.x || ^1.0.0",
"zod": "^3.x"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT",
"peer": true
},
"node_modules/axios": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz",
"integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==",
"license": "MIT",
"peer": true,
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"peer": true,
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"license": "MIT",
"peer": true,
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"peer": true,
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT",
"peer": true
},
"node_modules/typescript": {
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/zod": {
"version": "3.23.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}

View File

@@ -0,0 +1,31 @@
{
"name": "@solidtime/api",
"version": "0.0.1",
"description": "Package containing the solidtime api client and type declarations",
"main": "dist/index.js",
"scripts": {
"build": "npx ncc build src/index.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
"files": [
"dist"
],
"keywords": [
"solidtime",
"timetracker",
"timetracking",
"api",
"client"
],
"type": "module",
"author": "solidtime",
"license": "AGPL-3.0",
"dependencies": {
"@zodios/core": "^10.9.6",
"typescript": "^5.5.4",
"zod": "^3.23.8"
},
"devDependencies": {
"@vercel/ncc": "^0.38.1"
}
}

View File

@@ -4,8 +4,7 @@ import type {
ZodiosBodyByAlias,
ZodiosQueryParamsByAlias,
} from '@zodios/core';
import { createApiClient } from '../../../openapi.json.client';
import { router } from '@inertiajs/vue3';
import { createApiClient } from './openapi.json.client';
export type SolidTimeApi = ApiOf<typeof api>;
@@ -135,17 +134,4 @@ export type MyMemberships = ZodiosResponseByAlias<
export type MyMembership = MyMemberships[0];
export async function fetchToken() {
return new Promise((resolve) => {
router.reload({
onFinish: () => {
resolve(null);
},
});
});
}
export function isTokenValid() {
return window.document.cookie.includes('XSRF-TOKEN');
}
export const api = createApiClient('/api', { validate: 'none' });

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"noEmit": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"noImplicitThis": true,
"strict": true,
"verbatimModuleSyntax": true,
"target": "ESNext",
"useDefineForClassFields": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"outDir": "./dist",
"rootDir": "./src",
},
"include": [
"src/**/*.ts"
],
"exclude": [
"./dist",
"./node_modules",
"./__tests__",
"./coverage"
],
}

5
resources/js/packages/ui/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
node_modules
dist
out
.DS_Store
*.log*

1365
resources/js/packages/ui/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
{
"name": "@solidtime/ui",
"version": "0.0.1",
"description": "Package containing the solidtime ui components",
"main": "./dist/solidtime-ui-lib.umd.cjs",
"module": "./dist/solidtime-ui-lib.js",
"exports": {
".": {
"import": "./dist/solidtime-ui-lib.js",
"require": "./dist/solidtime-ui-lib.umd.cjs"
},
"./style.css": "./dist/style.css"
},
"types": "./dist/index.d.ts",
"scripts": {
"dev": "vite",
"build": "vite build && vue-tsc --emitDeclarationOnly",
"types": "vue-tsc ",
"preview": "vite preview"
},
"files": [
"dist"
],
"keywords": [
"solidtime",
"timetracker",
"timetracking",
"api",
"client"
],
"type": "module",
"author": "solidtime",
"license": "AGPL-3.0",
"dependencies": {
"@floating-ui/vue": "^1.1.4",
"tailwind-merge": "^2.5.2"
},
"devDependencies": {
"@types/node": "^22.4.1",
"@vitejs/plugin-vue": "^5.1.2",
"typescript": "^5.5.4",
"vite": "^5.4.1",
"vue": "^3.4.38",
"vue-tsc": "^2.0.29"
}
}

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import PrimaryButton from '@/Components/PrimaryButton.vue';
import DialogModal from '@/Components/DialogModal.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import PrimaryButton from './Buttons/PrimaryButton.vue';
import DialogModal from './DialogModal.vue';
import SecondaryButton from './Buttons/SecondaryButton.vue';
import { ArrowTopRightOnSquareIcon } from '@heroicons/vue/24/solid';
const show = defineModel('show', { default: false });

Some files were not shown because too many files have changed in this diff Show More