Reformat cards
This commit is contained in:
parent
4ca04b8cc8
commit
10b11f10dd
|
@ -4,5 +4,10 @@
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
"printWidth": 100,
|
"printWidth": 100,
|
||||||
"plugins": ["prettier-plugin-svelte"],
|
"plugins": ["prettier-plugin-svelte"],
|
||||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
"overrides": [
|
||||||
|
{ "files": "*.svelte", "options": { "parser": "svelte" } },
|
||||||
|
{ "files": "*.ts", "options": { "parser": "typescript" } },
|
||||||
|
{ "files": "*.js", "options": { "parser": "babel" } },
|
||||||
|
{ "files": "*.css", "options": { "parser": "css" } }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import type { Card } from '../stores/interfaces';
|
||||||
|
import api, { processError } from '../utils/api';
|
||||||
|
import status from '../utils/status';
|
||||||
|
|
||||||
|
export async function newCardApi(projectId: number): Promise<Card> {
|
||||||
|
const response = await api.post(`/v1/cards`, {
|
||||||
|
project_id: projectId,
|
||||||
|
title: 'Untitled',
|
||||||
|
content: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status !== status.Created) {
|
||||||
|
processError(response, 'Failed to create card');
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
const id: number = response.data.id;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: id,
|
||||||
|
project_id: projectId,
|
||||||
|
title: 'Untitled',
|
||||||
|
content: '',
|
||||||
|
tags: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteCardApi(cardID: number): Promise<void> {
|
||||||
|
const response = await api.delete(`/v2/cards/${cardID}`);
|
||||||
|
|
||||||
|
if (response.status !== status.NoContent) {
|
||||||
|
processError(response, 'Failed to delete card');
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { parseCards, type Card, type Project } from '../stores/interfaces';
|
||||||
|
import api, { processError } from '../utils/api';
|
||||||
|
import status from '../utils/status';
|
||||||
|
|
||||||
|
export async function getProjectAPI(projectId: number): Promise<Project> {
|
||||||
|
const response = await api.get(`/v1/projects/${projectId}`);
|
||||||
|
|
||||||
|
if (response.status !== status.OK) {
|
||||||
|
processError(response, 'Failed to fetch project');
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getProjectCardsAPI(projectId: number): Promise<Card[]> {
|
||||||
|
const response = await api.get(`/v1/projects/${projectId}/cards`);
|
||||||
|
|
||||||
|
if (response.status !== status.OK) {
|
||||||
|
processError(response, 'Failed to fetch cards');
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseCards(response.data);
|
||||||
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import currentModalCard from '../stores/currentModalCard';
|
||||||
import type { Card } from '../stores/interfaces';
|
import type { Card } from '../stores/interfaces';
|
||||||
import projectTags from '../stores/projectTags';
|
import projectTags from '../stores/projectTags';
|
||||||
import ModalCard from './modal_card.svelte';
|
import ModalCard from './modal_card.svelte';
|
||||||
|
|
||||||
export let card: Card;
|
export let card: Card;
|
||||||
export let showModal: boolean;
|
let showModal: boolean = $currentModalCard == card.id;
|
||||||
export let onDelete: () => void;
|
export let onDelete: () => void;
|
||||||
|
|
||||||
function editCard() {
|
function editCard() {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Card, TagOption } from '../stores/interfaces';
|
||||||
|
import CardC from './card.svelte';
|
||||||
|
|
||||||
|
export let tag_id: number;
|
||||||
|
export let option: TagOption;
|
||||||
|
export let cards: Card[] = [];
|
||||||
|
export let deleteCard: (id: number) => void;
|
||||||
|
|
||||||
|
let columnCards = cards.filter(
|
||||||
|
(card) => card.tags.find((t) => t.tag_id === tag_id)?.option_id === option.id
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="column">
|
||||||
|
<h3>{option.value}</h3>
|
||||||
|
<ul>
|
||||||
|
{#each columnCards as card}
|
||||||
|
<CardC {card} onDelete={async () => await deleteCard(card.id)} />
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h3 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
width: 200px;
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -2,105 +2,75 @@
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import CardC from './card.svelte';
|
import CardC from './card.svelte';
|
||||||
import { type Project, type Card, parseCards, type View } from '../stores/interfaces';
|
import { type Project, type Card, parseCards, type View } from '../stores/interfaces';
|
||||||
import status from '../utils/status';
|
|
||||||
import api, { processError } from '../utils/api';
|
|
||||||
import projectTags from '../stores/projectTags';
|
import projectTags from '../stores/projectTags';
|
||||||
import currentView from '../stores/currentView';
|
import currentView from '../stores/currentView';
|
||||||
import Card from './card.svelte';
|
import { deleteCardApi, newCardApi } from '../api/cards';
|
||||||
|
import { getProjectAPI, getProjectCardsAPI } from '../api/projects';
|
||||||
|
import Column from './column.svelte';
|
||||||
|
import currentModalCard from '../stores/currentModalCard';
|
||||||
|
|
||||||
export let projectId: number;
|
export let projectId: number;
|
||||||
|
|
||||||
let project: Project;
|
let project: Project;
|
||||||
let cards: Card[];
|
let cards: Card[] = [];
|
||||||
|
let view: View | null = null;
|
||||||
|
let columns: { id: number; title: string; cards: Card[] }[] = [];
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
let response = await api.get(`/v1/projects/${projectId}`);
|
getProjectAPI(projectId).then((p) => {
|
||||||
|
project = p;
|
||||||
|
});
|
||||||
|
|
||||||
if (response.status !== status.OK) {
|
getProjectCardsAPI(projectId).then((c) => {
|
||||||
processError(response, 'Failed to fetch project');
|
cards = parseCards(c);
|
||||||
return;
|
loadColumns();
|
||||||
}
|
});
|
||||||
|
|
||||||
project = response.data;
|
|
||||||
|
|
||||||
response = await api.get(`/v1/projects/${projectId}/cards`);
|
|
||||||
|
|
||||||
if (response.status === status.OK) {
|
|
||||||
cards = parseCards(response.data);
|
|
||||||
} else {
|
|
||||||
cards = [];
|
|
||||||
processError(response, 'Failed to fetch cards');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(await projectTags.init(projectId))) {
|
if (!(await projectTags.init(projectId))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentView.subscribe((v) => {
|
||||||
|
view = v;
|
||||||
|
loadColumns();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let modalID = -1;
|
function newCard() {
|
||||||
|
newCardApi(projectId).then((card) => {
|
||||||
async function newCard() {
|
cards = [...cards, card];
|
||||||
const response = await api.post(`/v1/cards`, {
|
currentModalCard.set(card.id);
|
||||||
project_id: projectId,
|
loadColumns();
|
||||||
title: 'Untitled',
|
|
||||||
content: ''
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.status !== status.Created) {
|
|
||||||
processError(response, 'Failed to create card');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id: number = response.data.id;
|
|
||||||
|
|
||||||
let card: Card = {
|
|
||||||
id: id,
|
|
||||||
project_id: projectId,
|
|
||||||
title: 'Untitled',
|
|
||||||
content: '',
|
|
||||||
tags: []
|
|
||||||
};
|
|
||||||
|
|
||||||
cards = [...cards, card];
|
|
||||||
modalID = id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteCard(cardID: number) {
|
function deleteCard(id: number) {
|
||||||
const response = await api.delete(`/v2/cards/${cardID}`);
|
deleteCardApi(id).then(() => {
|
||||||
|
cards = cards.filter((card) => card.id !== id);
|
||||||
if (response.status !== status.NoContent) {
|
loadColumns();
|
||||||
processError(response, 'Failed to delete card');
|
});
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cards = cards.filter((card) => card.id !== cardID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let view: View | null = null;
|
function loadColumns() {
|
||||||
let columns: { id: number; title: string; cards: Card[] }[] = [];
|
if (!view) return;
|
||||||
|
let primary_tag_id = view.primary_tag_id;
|
||||||
currentView.subscribe((v) => {
|
columns =
|
||||||
view = v;
|
$projectTags[primary_tag_id]?.options.map((o) => {
|
||||||
if (!v) return;
|
return {
|
||||||
let primary_tag_id = v.primary_tag_id;
|
id: o.id,
|
||||||
columns = $projectTags[primary_tag_id].options.map((o) => {
|
title: o.value,
|
||||||
return {
|
cards: cards.filter((c) => c.tags.map((t) => t.option_id).includes(o.id))
|
||||||
id: o.id,
|
};
|
||||||
title: o.value,
|
}) || [];
|
||||||
cards: cards.filter((c) => c.tags.map((t) => t.option_id).includes(o.id))
|
|
||||||
};
|
|
||||||
});
|
|
||||||
columns.push({
|
columns.push({
|
||||||
id: -1,
|
id: -1,
|
||||||
title: 'No tag',
|
title: 'No tag',
|
||||||
cards: cards.filter((c) => {
|
cards: cards.filter((c) => {
|
||||||
const tag = c.tags.find((t) => t.tag_id === primary_tag_id);
|
const tag = c.tags.find((t) => t.tag_id === primary_tag_id);
|
||||||
|
|
||||||
return tag?.option_id == -1;
|
return tag?.option_id == -1;
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
@ -115,25 +85,14 @@
|
||||||
<h2>{project.title}</h2>
|
<h2>{project.title}</h2>
|
||||||
<button on:click={newCard}>New card</button>
|
<button on:click={newCard}>New card</button>
|
||||||
</header>
|
</header>
|
||||||
{#if view}
|
{#if view && $projectTags[view.primary_tag_id]}
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
{#each columns as column}
|
{#each $projectTags[view.primary_tag_id].options as option}
|
||||||
<div class="column">
|
<Column tag_id={view.primary_tag_id} {option} bind:cards deleteCard />
|
||||||
<h3>{column.title}</h3>
|
|
||||||
<ul>
|
|
||||||
{#each column.cards as card}
|
|
||||||
<CardC
|
|
||||||
{card}
|
|
||||||
showModal={modalID === card.id}
|
|
||||||
onDelete={async () => await deleteCard(card.id)}
|
|
||||||
/>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<ul>
|
<!-- <ul>
|
||||||
{#if cards}
|
{#if cards}
|
||||||
{#each cards as card}
|
{#each cards as card}
|
||||||
<CardC
|
<CardC
|
||||||
|
@ -143,7 +102,7 @@
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</ul>
|
</ul> -->
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -16,12 +16,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
views = response.data;
|
views = response.data;
|
||||||
|
|
||||||
|
if (views.length > 0) currentView.set(views[0]);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<link rel="stylesheet" type="text/css" href="/css/sidebar.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="/css/sidebar.css" />
|
|
||||||
</svelte:head>
|
|
||||||
|
|
||||||
<div id="sidebar" class="sidebar">
|
<div id="sidebar" class="sidebar">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
export default writable(-1);
|
Loading…
Reference in New Issue