Add card from columns

This commit is contained in:
Brieuc Dubois 2024-01-08 22:14:16 +01:00
parent e7b34fc1b4
commit fb70658f23
5 changed files with 104 additions and 88 deletions

View File

@ -1,65 +1,56 @@
<script lang="ts"> <script lang="ts">
import cards from '$lib/stores/cards'; import Card from '$lib/types/Card';
import currentDraggedCard from '$lib/stores/currentDraggedCard';
import type Card from '$lib/types/Card';
import type TagValue from '$lib/types/TagValue';
import { get } from 'svelte/store';
import projectTags from '../../stores/projectTags';
import CardComponent from '../card/Card.svelte'; import CardComponent from '../card/Card.svelte';
import AddIcon from '../icons/AddIcon.svelte'; import AddIcon from '../icons/AddIcon.svelte';
import { import } from { createCardTagApi, deleteCardTagApi, updateCardTagApi }; import type TagOption from '$lib/types/TagOption';
import type ProjectTag from '$lib/types/ProjectTag';
import type Project from '$lib/types/Project';
export let projectId: number; export let project: Project;
export let optionId: number | null = null; export let option: TagOption | null = null;
export let primary_tag_id: number | null = null; export let primaryTag: ProjectTag | null = null;
export let title: string; export let title: string;
export let columnCards: Card[] = []; export let columnCards: Card[] = [];
let lastTitle = title; let lastTitle = title;
async function onDrop(e: DragEvent) { // async function onDrop(e: DragEvent) {
e.preventDefault(); // e.preventDefault();
if (!$currentDraggedCard || !$currentDraggedCard.tags) return; // if (!$currentDraggedCard || !$currentDraggedCard.cardTags) return;
for (let tag of $currentDraggedCard.tags) {
if (tag.tag_id !== primary_tag_id) continue;
if (tag.option_id == optionId) return;
try { // $currentDraggedCard;
if (tag.option_id && optionId) await deleteCardTagApi(tag.card_id, tag.tag_id);
else if (tag.option_id && optionId)
await createCardTagApi(tag.card_id, tag.tag_id, tag.option_id, tag.value);
else await updateCardTagApi(tag.card_id, tag.tag_id, optionId, tag.value);
tag.option_id = optionId; // for (let tag of $currentDraggedCard.cardTags) {
cards.reload(); // if (tag.projectTag !== primaryTag) continue;
} catch (e) {} // if (tag.option == option) return;
break;
} // if (!tag.option && !tag.value) await tag.delete();
currentDraggedCard.set(null); // else if (tag.option && optionId)
} // await createCardTagApi(tag.card_id, tag.tag_id, tag.option_id, tag.value);
// else await updateCardTagApi(tag.card_id, tag.tag_id, optionId, tag.value);
// tag.option_id = optionId;
// cards.reload();
// }
// currentDraggedCard.set(null);
// }
async function addCard() { async function addCard() {
const tags: TagValue[] = []; const card = await Card.create(project);
for (let tag of Object.values(get(projectTags))) {
if (tag.id === primary_tag_id) {
tags.push({
card_id: -1,
tag_id: tag.id,
option_id: optionId,
value: null
});
}
}
await cards.add(projectId, tags); if (!card) return;
if (!primaryTag) return;
if (!option) return;
await card.addTag(primaryTag, option, null);
} }
</script> </script>
<!-- on:drop={onDrop} -->
<div <div
class="column" class="column"
role="listbox" role="listbox"
tabindex="-1" tabindex="-1"
on:drop={onDrop}
on:dragover={(e) => { on:dragover={(e) => {
e.preventDefault(); e.preventDefault();
}} }}
@ -70,16 +61,17 @@
type="text" type="text"
on:blur={async () => { on:blur={async () => {
if (lastTitle === title) return; if (lastTitle === title) return;
if (!optionId || !primary_tag_id) return; if (!option || !primaryTag) return;
await updateTagOptionAPI({ // option;
id: optionId, // await updateTagOptionAPI({
tag_id: primary_tag_id, // id: optionId,
value: title // tag_id: primary_tag_id,
}); // value: title
lastTitle = title; // });
cards.reload(); // lastTitle = title;
// cards.reload();
}} }}
disabled={optionId === null} disabled={option === null}
/> />
<span> <span>
<span>{columnCards.length}</span> <span>{columnCards.length}</span>

View File

@ -1,6 +1,8 @@
<script lang="ts"> <script lang="ts">
import currentView from '$lib/stores/currentView'; import currentView from '$lib/stores/currentView';
import { cards } from '$lib/types/Card';
import type Project from '$lib/types/Project'; import type Project from '$lib/types/Project';
import Column from './Column.svelte';
import Header from './Header.svelte'; import Header from './Header.svelte';
export let project: Project; export let project: Project;
@ -12,44 +14,45 @@
<Header {project} /> <Header {project} />
{#if $cards} {#if $cards}
<div class="grid"> <div class="grid">
{#if view.primary_tag_id} {#if $currentView.primaryTag}
{#each $projectTags[view.primary_tag_id].options as option} {#each $currentView.primaryTag.options as option}
<Column <Column
optionId={option.id} {option}
primary_tag_id={view.primary_tag_id} primaryTag={$currentView.primaryTag}
title={option.value} title={option.value}
columnCards={$cards columnCards={$cards
.filter((c) => c.tags.map((t) => t.option_id).includes(option.id)) .filter((c) => c.cardTags.map((t) => t.option).includes(option))
.sort((a, b) => { .sort((a, b) => {
if (!view?.sort_tag_id) return 0; if (!$currentView?.sortTag) return 0;
const aTag = a.tags.find((t) => t.tag_id === view?.sort_tag_id); const aTag = a.cardTags.find((t) => t.projectTag === $currentView?.sortTag);
const bTag = b.tags.find((t) => t.tag_id === view?.sort_tag_id); const bTag = b.cardTags.find((t) => t.projectTag === $currentView?.sortTag);
if (!aTag) return -(view?.sort_direction || 1); if (!aTag) return -($currentView?.sortDirection || 1);
if (!bTag) return view?.sort_direction || 1; if (!bTag) return $currentView?.sortDirection || 1;
const aValue = aTag.value || aTag.option_id || 0; const aValue = aTag.value || aTag.option?.value || '';
const bValue = bTag.value || bTag.option_id || 0; const bValue = bTag.value || bTag.option?.value || '';
return aValue < bValue return aValue < bValue
? view?.sort_direction || 1 ? $currentView?.sortDirection || 1
: -(view?.sort_direction || 1); : -($currentView?.sortDirection || 1);
})} })}
projectId={project.id} {project}
/> />
{/each} {/each}
{/if} {/if}
<Column <Column
primary_tag_id={view.primary_tag_id} primaryTag={$currentView.primaryTag}
title={view.primary_tag_id title={$currentView.primaryTag ? `No ${$currentView.title}` : 'No groups'}
? `No ${$projectTags[view.primary_tag_id].title}` columnCards={$currentView.primaryTag != null
: 'No groups'} ? (() => {
columnCards={view.primary_tag_id const primaryTag = $currentView.primaryTag;
? $cards.filter( return $cards.filter(
(c) => !c.tags.map((t) => t.tag_id).includes(view?.primary_tag_id || -2) (c) => !c.cardTags.map((t) => t.projectTag).includes(primaryTag)
) );
})()
: $cards} : $cards}
projectId={project.id} {project}
/> />
</div> </div>
{/if} {/if}

View File

@ -3,6 +3,8 @@ import { get, writable } from 'svelte/store';
import CardTag from './CardTag'; import CardTag from './CardTag';
import Project from './Project'; import Project from './Project';
import { toastAlert } from '$lib/utils/toasts'; import { toastAlert } from '$lib/utils/toasts';
import type TagOption from './TagOption';
import type ProjectTag from './ProjectTag';
export const cards = writable([] as Card[]); export const cards = writable([] as Card[]);
@ -11,20 +13,20 @@ export default class Card {
private _project: Project; private _project: Project;
private _title: string; private _title: string;
private _content: string; private _content: string;
private _tags: CardTag[]; private _cardTags: CardTag[];
private constructor( private constructor(
id: number, id: number,
project: Project, project: Project,
title: string, title: string,
content: string, content: string,
tags: CardTag[] cardTags: CardTag[]
) { ) {
this._id = id; this._id = id;
this._project = project; this._project = project;
this._title = title; this._title = title;
this._content = content; this._content = content;
this._tags = tags; this._cardTags = cardTags;
} }
get id(): number { get id(): number {
@ -43,8 +45,8 @@ export default class Card {
return this._content; return this._content;
} }
get tags(): CardTag[] { get cardTags(): CardTag[] {
return this._tags; return this._cardTags;
} }
static fromId(id: number): Card | null { static fromId(id: number): Card | null {
@ -79,6 +81,20 @@ export default class Card {
return true; return true;
} }
async addTag(
projectTag: ProjectTag,
tagOption: TagOption | null,
value: string | null
): Promise<boolean> {
const cardTag = await CardTag.create(this, projectTag, tagOption, value);
if (!cardTag) return false;
this._cardTags.push(cardTag);
return true;
}
static parse(json: any): Card | null; static parse(json: any): Card | null;
static parse(json: any, project: Project | null | undefined): Card | null; static parse(json: any, project: Project | null | undefined): Card | null;
@ -95,7 +111,7 @@ export default class Card {
const card = new Card(json.id, project, json.title, json.content, []); const card = new Card(json.id, project, json.title, json.content, []);
card._tags = CardTag.parseAll(json.tags, card); card._cardTags = CardTag.parseAll(json.tags, card);
cards.update((cards) => { cards.update((cards) => {
if (!cards.find((c) => c.id === card.id)) { if (!cards.find((c) => c.id === card.id)) {

View File

@ -5,13 +5,18 @@ import TagOption from './TagOption';
export default class CardTag { export default class CardTag {
private _card: Card; private _card: Card;
private _tag: ProjectTag; private _projectTag: ProjectTag;
private _option: TagOption | null; private _option: TagOption | null;
private _value: string | null; private _value: string | null;
private constructor(card: Card, tag: ProjectTag, option: TagOption | null, value: string | null) { private constructor(
card: Card,
projectTag: ProjectTag,
option: TagOption | null,
value: string | null
) {
this._card = card; this._card = card;
this._tag = tag; this._projectTag = projectTag;
this._option = option; this._option = option;
this._value = value; this._value = value;
} }
@ -20,11 +25,11 @@ export default class CardTag {
return this.card; return this.card;
} }
get tag(): number { get projectTag(): ProjectTag {
return this.tag; return this.projectTag;
} }
get option(): number | null { get option(): TagOption | null {
return this.option; return this.option;
} }
@ -46,7 +51,7 @@ export default class CardTag {
} }
async delete() { async delete() {
return cardsTagsApi.delete(this._card.id, this._tag.id); return cardsTagsApi.delete(this._card.id, this._projectTag.id);
} }
static parse(json: any): CardTag | null; static parse(json: any): CardTag | null;

View File

@ -15,7 +15,7 @@ export default class TagOption {
return this._id; return this._id;
} }
get tagId(): ProjectTag { get projectTag(): ProjectTag {
return this._projectTag; return this._projectTag;
} }