All checks were successful
Build and Deploy Nuxt / build (push) Successful in 52s
151 lines
3.3 KiB
Vue
151 lines
3.3 KiB
Vue
<script setup>
|
|
import { computed, onMounted, ref } from 'vue';
|
|
import { SetupHandle, SetSize, ResetPosition, Top, ClearWindow } from '@/services/Windows';
|
|
import WindowHandle from './partials/WindowHandle.vue';
|
|
import Server from '~/services/Server';
|
|
import { emitter } from '~/services/Emitter';
|
|
import { useCampaignService } from '~/services/Campaign';
|
|
|
|
const handle = ref(null);
|
|
const wrapper = ref(null);
|
|
|
|
const props = defineProps(['data']);
|
|
const data = props.data;
|
|
|
|
const { Campaign } = useCampaignService();
|
|
|
|
const id = data.id;
|
|
const title = ref('');
|
|
const content = ref('');
|
|
const isSaving = ref(false);
|
|
const error = ref('');
|
|
|
|
const campaignId = computed(() => {
|
|
return Campaign.value?._id ?? Campaign.value?.id ?? null;
|
|
});
|
|
|
|
onMounted(() => {
|
|
Top(wrapper);
|
|
SetupHandle(id, handle);
|
|
SetSize(id, { width: 640, height: 520 });
|
|
ResetPosition(id, "center");
|
|
});
|
|
|
|
async function createNote() {
|
|
if (!campaignId.value || isSaving.value) {
|
|
return;
|
|
}
|
|
|
|
isSaving.value = true;
|
|
error.value = '';
|
|
|
|
try {
|
|
const response = await Server().post('/note/create', {
|
|
title: title.value.trim() || 'Untitled Note',
|
|
content: content.value,
|
|
campaign: campaignId.value
|
|
});
|
|
|
|
if (response.data.status !== 'ok') {
|
|
error.value = response.data.msg ?? 'Unable to create note.';
|
|
return;
|
|
}
|
|
|
|
emitter.emit('note-created', response.data.note);
|
|
ClearWindow({ id });
|
|
} catch (err) {
|
|
error.value = 'Unable to create note.';
|
|
} finally {
|
|
isSaving.value = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="window-wrapper" :id="'window-wrapper-' + id" ref="wrapper">
|
|
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
|
|
|
<div class="body">
|
|
<form @submit.prevent="createNote">
|
|
<div class="form-field">
|
|
<label>Title</label>
|
|
<input v-model="title" type="text" name="noteTitle" placeholder="Enter a note title" autocomplete="off">
|
|
</div>
|
|
|
|
<div class="form-field stacked">
|
|
<label>Content</label>
|
|
<textarea v-model="content" name="noteContent" placeholder="Write your note here"></textarea>
|
|
</div>
|
|
|
|
<div v-if="error" class="form-error">
|
|
{{ error }}
|
|
</div>
|
|
|
|
<div class="form-actions">
|
|
<button class="btn-primary sound-click" :disabled="isSaving">
|
|
{{ isSaving ? 'Creating...' : 'Create Note' }}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.window-wrapper {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.body {
|
|
width: 100%;
|
|
}
|
|
|
|
form {
|
|
margin: 10px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.form-field {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.form-field > * {
|
|
flex: 1;
|
|
}
|
|
|
|
.stacked {
|
|
align-items: stretch;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
|
|
label {
|
|
text-align: left;
|
|
}
|
|
|
|
textarea {
|
|
min-height: 300px;
|
|
resize: vertical;
|
|
}
|
|
|
|
.form-error {
|
|
color: #9e2a2b;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.form-actions {
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
.form-actions button {
|
|
width: 100%;
|
|
}
|
|
</style>
|