Skip to content

Commit

Permalink
merge pull request #39 from mnenie/dev
Browse files Browse the repository at this point in the history
feat: add projects and add workspace tests, chore: update router
  • Loading branch information
mnenie authored Aug 22, 2024
2 parents 6f60d6c + 3095000 commit 2aeaf78
Show file tree
Hide file tree
Showing 14 changed files with 261 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/app/providers/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const routes = [
component: () => import('@/pages/NotFoundPage.vue'),
meta: {
layout: LayoutsEnum.auth,
requiresAuth: true
requiresAuth: false
}
}
] satisfies readonly RouterRecord[];
Expand Down
9 changes: 3 additions & 6 deletions src/entities/board/model/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,14 @@ export type Status = 'work' | 'archive' | 'closed' | 'not active';

export interface BoardPreview extends DateParams {
_id: string;
title: string;
description: string;
name: string;
description?: string;
users: User[];
}

export interface Board extends DateParams {
_id: string;
export interface Board extends BoardPreview, DateParams {
columns?: Column[];
name: string;
color?: string;
users: User[];
status: Status;
}

Expand Down
2 changes: 1 addition & 1 deletion src/entities/board/ui/BoardPreviewCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const userPosition = computed(() => {
<template>
<div :class="$style.active_board" @click="$router.push('/board/1')">
<div :class="$style.text">
<p class="text-base" style="font-weight: 500">{{ board.title }}</p>
<p class="text-base" style="font-weight: 500">{{ board.name }}</p>
<span class="text-xs">{{ board.description }}</span>
</div>
<div :class="$style.bottom_part">
Expand Down
2 changes: 1 addition & 1 deletion src/entities/board/ui/__tests__/BoardPreviewCard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('tests for BoardPreviewCard.vue', () => {
props: {
board: {
_id: '0',
title: 'test title',
name: 'test title',
description: 'test description',
users: []
}
Expand Down
4 changes: 2 additions & 2 deletions src/layouts/ui/DefaultLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { Splitpanes, Pane } from 'splitpanes';
import 'splitpanes/dist/splitpanes.css';
import { computed, ref } from 'vue';
import { Sidebar, HeaderMain } from '@/widgets/layout';
import { AppSidebar, HeaderMain } from '@/widgets/layout';
import { useLocalStorage } from '@vueuse/core';
import { RouteNames } from '@/shared/config/consts';
import { useWindowSize } from '@vueuse/core';
Expand Down Expand Up @@ -33,7 +33,7 @@ const onToggleArea = () => {
:size="widthSidebar"
:style="{ transition: transitionFl && 'width .2s ease-out' }"
>
<Sidebar :is-expanded @on-toggle="onToggleArea" />
<AppSidebar :is-expanded @on-toggle="onToggleArea" />
</Pane>
<Pane :size="widthMainContainer">
<div :class="$style.main_part">
Expand Down
1 change: 1 addition & 0 deletions src/shared/lib/i18n/locales/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export default {
badge: 'free',
input: 'Search',
section: 'workspace',
projects: 'projects',
boards: 'Boards',
templates: 'Templates',
members: 'Members',
Expand Down
1 change: 1 addition & 0 deletions src/shared/lib/i18n/locales/ru-RU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export default {
badge: 'free',
input: 'Поиск',
section: 'рабочее пространство',
projects: 'проекты',
boards: 'Доски',
templates: 'Шаблоны',
members: 'Участники',
Expand Down
1 change: 1 addition & 0 deletions src/shared/lib/i18n/locales/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export default {
badge: '免费',
input: '搜索',
section: '工作区',
projects: '项目',
boards: '看板',
templates: '模板',
members: '成员',
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/boards/ui/TeamBoards.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const { t } = useI18n();
const boards = ref<BoardPreview[]>([
{
_id: '0',
title: 'GTM Campaign',
name: 'GTM Campaign',
description: 'crm system development',
users: [
{ _id: '0', email: 'al', photoUrl: 'https://www.shadcn-vue.com/avatars/02.png' },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed } from 'vue';
import { computed, ref } from 'vue';
import { useDark } from '@vueuse/core';
import { useI18n } from 'vue-i18n';
import { UiBadge } from '@/shared/ui';
Expand All @@ -9,6 +9,8 @@ import { SearchFilter } from '@/features/filter';
import { PlanCard } from '@/features/plan';
import { ArrowsDouble } from '@/shared/assets/icons';
import { AlignJustify } from 'lucide-vue-next';
import ProjectsList from './ProjectsList.vue';
import type { Board } from '@/entities/board';
const props = defineProps<{
isExpanded: boolean;
Expand All @@ -31,6 +33,13 @@ const { t } = useI18n();
const iconUrl = computed(() => {
return isDark.value ? '/icons/kanban-dark.png' : '/icons/kanban.png';
});
// mock -> after data from backend
//@ts-ignore
const boards = ref<Board[]>([
{ _id: '0', name: 'test', users: [], status: 'work', color: '#a1612a' },
{ _id: '1', name: 'New board', users: [], status: 'work', color: '#45ad2d' }
]);
</script>

<template>
Expand All @@ -53,6 +62,7 @@ const iconUrl = computed(() => {
<div>
<SearchFilter :is-expanded @on-toggle="emit('onToggle')" />
<WorkSpace :links :is-expanded />
<ProjectsList :boards :is-expanded />
</div>
<PlanCard :is-expanded />
</div>
Expand Down
153 changes: 153 additions & 0 deletions src/widgets/layout/ui/sidebar/ProjectsList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
<script setup lang="ts">
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { UiButton } from '@/shared/ui';
import type { Board } from '@/entities/board';
import { CircleFadingPlus } from 'lucide-vue-next';
import { useDark } from '@vueuse/core';
const props = defineProps<{
boards: Board[];
isExpanded: boolean;
}>();
const route = useRoute();
const isCurrentPath = (project: Board) =>
computed(() => {
return project._id === route.params.id && route.params.id !== undefined;
});
const _projects = computed(() => {
return props.boards.map((proj) => ({
...proj,
isActive: isCurrentPath(proj).value
}));
});
const { t } = useI18n();
const isDark = useDark();
const contentPosition = computed(() => {
return props.isExpanded ? 'flex-start' : 'center';
});
const projectName = computed(() => {
return (project: Board) => {
return project.name.slice(0, 1);
};
});
</script>

<template>
<div :class="$style.about">
<p class="text-sm" :class="$style.section">{{ t('sidebar.projects') }}</p>
<CircleFadingPlus
v-if="isExpanded"
:size="14"
:color="!isDark ? 'var(--zinc-800)' : 'var(--zinc-300)'"
style="cursor: pointer;"
/>
</div>
<div :class="$style.sidebar_projects">
<RouterLink
v-for="project in _projects"
:key="project._id"
v-tooltip.right="{
content: project.name,
triggers: ['hover'],
disabled: isExpanded
}"
:to="`/board/${project._id}`"
:class="$style.project"
>
<UiButton
:variant="project.isActive ? 'secondary' : 'ghost'"
:class="$style.proj_btn"
:style="{ padding: !isExpanded ? '0px' : '' }"
>
<div :class="$style.project_indicator" :style="{ backgroundColor: project.color }">
{{ projectName(project) }}
</div>
<span v-show="isExpanded" class="text-sm">{{ project.name }}</span>
</UiButton>
</RouterLink>
</div>
</template>

<style module lang="scss">
@import '@/app/styles/mixins';
.about {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
margin-bottom: 12px;
.section {
color: var(--zinc-300);
text-transform: uppercase;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
.sidebar_projects {
display: flex;
flex-direction: column;
gap: 5px;
justify-content: flex-start;
margin-bottom: 30px;
.project {
display: flex;
align-items: center;
gap: 6px;
cursor: pointer;
color: var(--zinc-900);
justify-content: flex-start;
width: 100%;
.proj_btn {
width: 100%;
justify-content: v-bind('contentPosition');
gap: 6px;
box-shadow: none;
.project_indicator {
width: 20px;
height: 20px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
color: var(--zinc-50);
// text-transform: lowercase;
}
}
& span {
font-weight: 500 !important;
color: var(--zinc-900);
}
}
}
:global(html.dark) {
.sidebar_projects {
.project {
.proj_btn {
& span {
color: var(--zinc-100);
}
&:hover {
background-color: var(--zinc-700);
}
}
}
}
}
</style>
61 changes: 61 additions & 0 deletions src/widgets/layout/ui/sidebar/__tests__/WorkSpace.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { describe, it, expect, vi } from 'vitest';
import { mount, RouterLinkStub } from '@vue/test-utils';
import WorkSpace from '../WorkSpace.vue';
import i18n from '@/shared/lib/i18n';
import { RouteNames } from '@/shared/config/consts';
import { h } from 'vue';
import { SquareDashedKanban } from 'lucide-vue-next';
import { useRoute } from 'vue-router';

vi.mock('vue-router');

vi.mock('@vueuse/integrations/useCookies', () => {
return {
useCookies: () => ({
get(key: string) {
return key === 'i18n' ? 'en-US' : undefined;
}
})
};
});

describe('tests for WorkSpace.vue', () => {
//@ts-expect-error mock types
useRoute.mockReturnValue({
name: RouteNames.boards
});
const wrapper = mount(WorkSpace, {
global: {
plugins: [i18n],
mocks: {
t: (key: string) => {
const translations: Record<string, string> = {
'sidebar.boards': 'boards',
'sidebar.section': 'workspace'
};
return translations[key];
}
},
stubs: {
RouterLink: RouterLinkStub
},
directives: {
tooltip() {}
}
},
props: {
isExpanded: true,
links: [{ id: 0, title: 'boards', pathName: RouteNames.boards, icon: h(SquareDashedKanban) }]
}
});

it('should be render correctly', () => {
expect(wrapper.html()).toMatchSnapshot();
});

it('should be redirect with RouterLink correctly', () => {
expect(wrapper.findComponent(RouterLinkStub).props('to')).toEqual({
name: RouteNames.boards
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`tests for WorkSpace.vue > should be render correctly 1`] = `
"<p class="name_block text-sm">workspace</p>
<div class="sidebar_main_links"><a class="link"><button class="text-sm button secondary md link_btn"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="rgb(82 82 91 / 0.9)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-square-dashed-kanban-icon">
<path d="M8 7v7"></path>
<path d="M12 7v4"></path>
<path d="M16 7v9"></path>
<path d="M5 3a2 2 0 0 0-2 2"></path>
<path d="M9 3h1"></path>
<path d="M14 3h1"></path>
<path d="M19 3a2 2 0 0 1 2 2"></path>
<path d="M21 9v1"></path>
<path d="M21 14v1"></path>
<path d="M21 19a2 2 0 0 1-2 2"></path>
<path d="M14 21h1"></path>
<path d="M9 21h1"></path>
<path d="M5 21a2 2 0 0 1-2-2"></path>
<path d="M3 14v1"></path>
<path d="M3 9v1"></path>
</svg><span class="text-sm">boards</span></button></a></div>"
`;
4 changes: 2 additions & 2 deletions src/widgets/layout/ui/sidebar/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import Sidebar from './Sidebar.vue';
import AppSidebar from './AppSidebar.vue';

export { Sidebar };
export { AppSidebar };

0 comments on commit 2aeaf78

Please sign in to comment.