This commit is contained in:
parent
6d70187cb9
commit
c578538fe0
10 changed files with 195 additions and 107 deletions
|
|
@ -36,7 +36,7 @@ return [
|
||||||
$newFile = $page->createFile([
|
$newFile = $page->createFile([
|
||||||
'source' => $upload['tmp_name'],
|
'source' => $upload['tmp_name'],
|
||||||
'filename' => $name,
|
'filename' => $name,
|
||||||
'template' => 'document',
|
'template' => 'pdf',
|
||||||
'content' => [
|
'content' => [
|
||||||
'date' => date('Y-m-d h:i')
|
'date' => date('Y-m-d h:i')
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,11 @@ function getFileData($file) {
|
||||||
'name' => $file->filename(),
|
'name' => $file->filename(),
|
||||||
'label' => (string) $file->label(),
|
'label' => (string) $file->label(),
|
||||||
'type' => (string) $file->type(),
|
'type' => (string) $file->type(),
|
||||||
|
'cover' => $file->cover()->isNotEmpty() ? $file->cover()->toFile()->thumb([
|
||||||
|
'width' => 1000,
|
||||||
|
'quality' => 80,
|
||||||
|
'format' => 'webp'
|
||||||
|
])->url() : null
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($file->description()->exists()) {
|
if ($file->description()->exists()) {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,11 @@
|
||||||
:class="{ active: isCurrent(project) }"
|
:class="{ active: isCurrent(project) }"
|
||||||
>
|
>
|
||||||
<router-link
|
<router-link
|
||||||
:to="project.uri"
|
:to="
|
||||||
|
isEmptyBrief(project)
|
||||||
|
? project.uri + '/client-brief'
|
||||||
|
: project.uri
|
||||||
|
"
|
||||||
:class="hasUnreadNotification(project) ? 'new' : undefined"
|
:class="hasUnreadNotification(project) ? 'new' : undefined"
|
||||||
@click="collapse()"
|
@click="collapse()"
|
||||||
>{{ project.title }}</router-link
|
>{{ project.title }}</router-link
|
||||||
|
|
@ -107,11 +111,13 @@ import { useProjectsStore } from "../stores/projects";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { useUserStore } from "../stores/user";
|
import { useUserStore } from "../stores/user";
|
||||||
import { usePageStore } from "../stores/page";
|
import { usePageStore } from "../stores/page";
|
||||||
|
import { useProjectStore } from "../stores/project";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const isExpanded = ref(true);
|
const isExpanded = ref(true);
|
||||||
const { user } = storeToRefs(useUserStore());
|
const { user } = storeToRefs(useUserStore());
|
||||||
const { currentProjects, archivedProjects } = storeToRefs(useProjectsStore());
|
const { currentProjects, archivedProjects } = storeToRefs(useProjectsStore());
|
||||||
|
const { isEmptyBrief } = useProjectStore();
|
||||||
const { page } = storeToRefs(usePageStore());
|
const { page } = storeToRefs(usePageStore());
|
||||||
|
|
||||||
const unreadNotificationsCount = computed(() => {
|
const unreadNotificationsCount = computed(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<router-link :to="project.uri">
|
<router-link
|
||||||
|
:to="isEmptyBrief(project) ? project.uri + '/client-brief' : project.uri"
|
||||||
|
>
|
||||||
<article class="project-item | flex | rounded-2xl | px-32 py-32">
|
<article class="project-item | flex | rounded-2xl | px-32 py-32">
|
||||||
<hgroup>
|
<hgroup>
|
||||||
<h3>{{ project.title }}</h3>
|
<h3>{{ project.title }}</h3>
|
||||||
|
|
@ -11,7 +13,11 @@
|
||||||
</p>
|
</p>
|
||||||
</hgroup>
|
</hgroup>
|
||||||
<img :src="project.logo" alt="Logo" class="project-logo | rounded-sm" />
|
<img :src="project.logo" alt="Logo" class="project-logo | rounded-sm" />
|
||||||
<ol class="project-steps" :data-steps="project.steps.length" :style="'--steps:'+project.steps.length">
|
<ol
|
||||||
|
class="project-steps"
|
||||||
|
:data-steps="project.steps.length"
|
||||||
|
:style="'--steps:' + project.steps.length"
|
||||||
|
>
|
||||||
<li
|
<li
|
||||||
v-for="step in project.steps"
|
v-for="step in project.steps"
|
||||||
class="project-step"
|
class="project-step"
|
||||||
|
|
@ -39,5 +45,5 @@ const frenchFormattedModified = dayjs(project.modified).format(
|
||||||
"dddd D MMMM YYYY"
|
"dddd D MMMM YYYY"
|
||||||
);
|
);
|
||||||
|
|
||||||
const { stepsLabels, setStatus } = useProjectStore();
|
const { stepsLabels, setStatus, isEmptyBrief } = useProjectStore();
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,15 @@
|
||||||
>
|
>
|
||||||
<hgroup class="order-last">
|
<hgroup class="order-last">
|
||||||
<h3 class="card__title | font-serif | text-lg">
|
<h3 class="card__title | font-serif | text-lg">
|
||||||
<router-link :to="'/' + step.uri" class="link-full">{{
|
<router-link
|
||||||
step.label
|
:to="
|
||||||
}}</router-link>
|
step.id === 'clientBrief'
|
||||||
|
? '/' + page.uri + '/client-brief'
|
||||||
|
: '/' + step.uri
|
||||||
|
"
|
||||||
|
class="link-full"
|
||||||
|
>{{ step.label }}</router-link
|
||||||
|
>
|
||||||
</h3>
|
</h3>
|
||||||
</hgroup>
|
</hgroup>
|
||||||
<div class="card__meta | flex">
|
<div class="card__meta | flex">
|
||||||
|
|
@ -42,17 +48,20 @@
|
||||||
<figure
|
<figure
|
||||||
v-if="step.id === 'clientBrief' && step.files[0]?.type === 'image'"
|
v-if="step.id === 'clientBrief' && step.files[0]?.type === 'image'"
|
||||||
class="card__images"
|
class="card__images"
|
||||||
:data-count="step.files.length"
|
:data-count="
|
||||||
|
step.files.filter((file) => file.type === 'image').length
|
||||||
|
"
|
||||||
:data-plus="
|
:data-plus="
|
||||||
step.files.length > 3 ? step.files.length - 3 : undefined
|
step.files.length > 3 ? step.files.length - 3 : undefined
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<img
|
<template v-for="image in step.files.slice(0, 3)" :key="image.uuid">
|
||||||
v-for="image in step.files.slice(0, 3)"
|
<img
|
||||||
:key="image.uuid"
|
v-if="image.type === 'image'"
|
||||||
:src="image.url"
|
:src="image.url"
|
||||||
:alt="image.alt"
|
:alt="image.alt"
|
||||||
/>
|
/>
|
||||||
|
</template>
|
||||||
</figure>
|
</figure>
|
||||||
<figure
|
<figure
|
||||||
v-if="step.id === 'virtualSample'"
|
v-if="step.id === 'virtualSample'"
|
||||||
|
|
@ -87,70 +96,93 @@
|
||||||
</footer>
|
</footer>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
<template v-if="step.id === 'clientBrief' && hasOneBriefType()">
|
||||||
|
<button
|
||||||
|
v-if="step.files[0].type === 'document'"
|
||||||
|
class="btn | w-full"
|
||||||
|
@click="toImagesBrief()"
|
||||||
|
>
|
||||||
|
Ajouter un brief via la plateforme
|
||||||
|
</button>
|
||||||
|
<div class="btn | w-full" v-else>
|
||||||
|
<label for="upload-pdf">
|
||||||
|
Ajouter brief PDF
|
||||||
|
<input
|
||||||
|
id="upload-pdf"
|
||||||
|
type="file"
|
||||||
|
@change="addPdf($event, step.uri)"
|
||||||
|
accept="application/pdf"
|
||||||
|
ref="pdfInput"
|
||||||
|
hidden
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template
|
<template
|
||||||
v-if="
|
v-if="
|
||||||
|
(step.id == 'clientBrief' &&
|
||||||
|
step.files.find((file) => file.type === 'document')) ||
|
||||||
step.id == 'proposal' ||
|
step.id == 'proposal' ||
|
||||||
(step.id == 'industrialIdeation' && step.files.length)
|
(step.id == 'industrialIdeation' && step.files.length)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<article
|
<template v-for="(file, index) in step.files" :key="file.name">
|
||||||
class="card"
|
<article class="card" v-if="file.type === 'document'">
|
||||||
v-for="(file, index) in step.files"
|
<hgroup class="order-last">
|
||||||
:key="file.name"
|
<h3 class="card__title | font-serif | text-lg">
|
||||||
>
|
<router-link
|
||||||
<hgroup class="order-last">
|
:to="'/' + step.uri + '&fileIndex=' + index"
|
||||||
<h3 class="card__title | font-serif | text-lg">
|
class="link-full"
|
||||||
<router-link
|
>
|
||||||
:to="'/' + step.uri + '&fileIndex=' + index"
|
{{
|
||||||
class="link-full"
|
file.label.length
|
||||||
|
? file.label
|
||||||
|
: file.name.replace(".pdf", "")
|
||||||
|
}}
|
||||||
|
</router-link>
|
||||||
|
</h3>
|
||||||
|
</hgroup>
|
||||||
|
<div class="card__meta | flex">
|
||||||
|
<time
|
||||||
|
class="card__date | text-grey-700"
|
||||||
|
:datetime="dayjs(file.modified).format('YYYY-M-DD')"
|
||||||
|
>{{ dayjs(file.modified).format("DD MMMM YYYY") }}</time
|
||||||
>
|
>
|
||||||
{{
|
</div>
|
||||||
file.label.length
|
<template v-if="step.id === 'clientBrief' || index === 0">
|
||||||
? file.label
|
<figure
|
||||||
: file.name.replace(".pdf", "")
|
v-if="file.cover"
|
||||||
}}
|
class="card__images pdf-cover"
|
||||||
</router-link>
|
style="aspect-ratio: unset"
|
||||||
</h3>
|
|
||||||
</hgroup>
|
|
||||||
<div class="card__meta | flex">
|
|
||||||
<time
|
|
||||||
class="card__date | text-grey-700"
|
|
||||||
:datetime="dayjs(file.modified).format('YYYY-M-DD')"
|
|
||||||
>{{ dayjs(file.modified).format("DD MMMM YYYY") }}</time
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<template v-if="index === 0">
|
|
||||||
<figure
|
|
||||||
v-if="file.cover"
|
|
||||||
class="card__images pdf-cover"
|
|
||||||
style="aspect-ratio: unset"
|
|
||||||
>
|
|
||||||
<img :src="file.cover" alt="" />
|
|
||||||
</figure>
|
|
||||||
<div v-else class="card__images" data-icon="document"></div>
|
|
||||||
</template>
|
|
||||||
<footer
|
|
||||||
v-if="file.comments?.length > 0"
|
|
||||||
class="order-last | text-sm text-primary font-medium"
|
|
||||||
>
|
|
||||||
<template v-if="step.id === 'proposal'">
|
|
||||||
<router-link
|
|
||||||
:to="'/' + step.uri + '&fileIndex=' + index + '&comments'"
|
|
||||||
>
|
>
|
||||||
{{ file.comments.length }} commentaire{{
|
<img :src="file.cover" alt="" />
|
||||||
file.comments.length > 1 ? "s" : ""
|
</figure>
|
||||||
}}
|
<div v-else class="card__images" data-icon="document"></div>
|
||||||
</router-link>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<footer
|
||||||
<router-link :to="'/' + step.uri + '&comments=true'">
|
v-if="file.comments?.length > 0"
|
||||||
{{ file.comments.length }} commentaire{{
|
class="order-last | text-sm text-primary font-medium"
|
||||||
file.comments.length > 1 ? "s" : ""
|
>
|
||||||
}}
|
<template v-if="step.id === 'proposal'">
|
||||||
</router-link>
|
<router-link
|
||||||
</template>
|
:to="'/' + step.uri + '&fileIndex=' + index + '&comments'"
|
||||||
</footer>
|
>
|
||||||
</article>
|
{{ file.comments.length }} commentaire{{
|
||||||
|
file.comments.length > 1 ? "s" : ""
|
||||||
|
}}
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<router-link :to="'/' + step.uri + '&comments=true'">
|
||||||
|
{{ file.comments.length }} commentaire{{
|
||||||
|
file.comments.length > 1 ? "s" : ""
|
||||||
|
}}
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -189,16 +221,20 @@ import "dayjs/locale/fr";
|
||||||
import { usePageStore } from "../../stores/page";
|
import { usePageStore } from "../../stores/page";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { useProjectStore } from "../../stores/project";
|
import { useProjectStore } from "../../stores/project";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import { useBriefStore } from "../../stores/brief";
|
||||||
|
|
||||||
const { step } = defineProps({
|
const { step } = defineProps({
|
||||||
step: Object,
|
step: Object,
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["update:file"]);
|
const emit = defineEmits(["update:file"]);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
dayjs.locale("fr");
|
dayjs.locale("fr");
|
||||||
|
|
||||||
const { page } = usePageStore();
|
const { page } = usePageStore();
|
||||||
|
const { addPdf } = useBriefStore();
|
||||||
const { setStatus } = useProjectStore();
|
const { setStatus } = useProjectStore();
|
||||||
|
|
||||||
const steps = page.steps.map((item) => {
|
const steps = page.steps.map((item) => {
|
||||||
|
|
@ -225,6 +261,16 @@ function getFrontView(track) {
|
||||||
const frontView = track.files.find((file) => file.name === frontViewName);
|
const frontView = track.files.find((file) => file.name === frontViewName);
|
||||||
return frontView;
|
return frontView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasOneBriefType() {
|
||||||
|
const hasImage = step.files.some((file) => file.type === "image");
|
||||||
|
const hasDocument = step.files.some((file) => file.type === "document");
|
||||||
|
return hasImage ^ hasDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toImagesBrief() {
|
||||||
|
router.push(location.pathname + "/client-brief?step=images");
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ watch(isOpen, (newValue) => {
|
||||||
|
|
||||||
openedFile.value = route.query.fileIndex
|
openedFile.value = route.query.fileIndex
|
||||||
? dialog.content.files[route.query.fileIndex]
|
? dialog.content.files[route.query.fileIndex]
|
||||||
: dialog.content.files[0];
|
: dialog.content.files.find((file) => file.type === "document");
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
async function validate() {
|
async function validate() {
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
<input
|
<input
|
||||||
id="upload-pdf"
|
id="upload-pdf"
|
||||||
type="file"
|
type="file"
|
||||||
@change="addPdf($event)"
|
@change="addPdf($event, page.uri, true)"
|
||||||
accept="application/pdf"
|
accept="application/pdf"
|
||||||
ref="pdfInput"
|
ref="pdfInput"
|
||||||
hidden
|
hidden
|
||||||
|
|
@ -96,45 +96,13 @@
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { usePageStore } from "../../../stores/page";
|
import { usePageStore } from "../../../stores/page";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
|
import { useBriefStore } from "../../../stores/brief";
|
||||||
|
|
||||||
const emit = defineEmits("update:step");
|
const emit = defineEmits("update:step");
|
||||||
|
|
||||||
const { page } = storeToRefs(usePageStore());
|
const { page } = storeToRefs(usePageStore());
|
||||||
|
const { addPdf } = useBriefStore();
|
||||||
const pdfInput = ref(null);
|
const pdfInput = ref(null);
|
||||||
|
|
||||||
async function addPdf(event) {
|
|
||||||
const file = event.target.files[0];
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("file", file);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(
|
|
||||||
"/upload-pdf.json?pageUri=" + page.value.uri,
|
|
||||||
{
|
|
||||||
method: "POST",
|
|
||||||
body: formData,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
console.log("File uploaded successfully.");
|
|
||||||
page.value = result;
|
|
||||||
location.href =
|
|
||||||
location.origin + "/" + page.value.parent + "?dialog=client-brief";
|
|
||||||
} else {
|
|
||||||
console.error("Error uploading file:", result.error);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Request failed:", error);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.error("No file selected.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
45
src/stores/brief.js
Normal file
45
src/stores/brief.js
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { usePageStore } from "./page";
|
||||||
|
|
||||||
|
export const useBriefStore = defineStore("brief", () => {
|
||||||
|
async function addPdf(event, briefUri, redirectToParent = false) {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
const { page } = usePageStore();
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", file);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/upload-pdf.json?pageUri=" + briefUri, {
|
||||||
|
method: "POST",
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
page.value = result;
|
||||||
|
if (redirectToParent) {
|
||||||
|
location.href =
|
||||||
|
location.origin +
|
||||||
|
"/" +
|
||||||
|
page.value.parent +
|
||||||
|
"?dialog=client-brief";
|
||||||
|
} else {
|
||||||
|
location.href = location.href + "?dialog=client-brief";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error("Error uploading file:", result.error);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Request failed:", error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error("No file selected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { addPdf };
|
||||||
|
});
|
||||||
|
|
@ -30,5 +30,12 @@ export const useProjectStore = defineStore("project", () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { stepsLabels, setStatus };
|
function isEmptyBrief(project) {
|
||||||
|
return (
|
||||||
|
project.currentStep === "clientBrief" &&
|
||||||
|
project.steps[0].files.length === 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { stepsLabels, setStatus, isEmptyBrief };
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
class="btn | ml-auto"
|
class="btn | ml-auto"
|
||||||
@click="validate"
|
@click="validate"
|
||||||
v-if="page.content.isvalidated != 'true'"
|
v-if="page.content.isvalidated != 'true'"
|
||||||
|
:disabled="page.files.length === 0"
|
||||||
>
|
>
|
||||||
Valider et envoyer le brief
|
Valider et envoyer le brief
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -29,6 +30,7 @@ import TitledPdfWrapper from "../components/project/TitledPdfWrapper.vue";
|
||||||
import { usePageStore } from "../stores/page";
|
import { usePageStore } from "../stores/page";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { useApiStore } from "../stores/api";
|
import { useApiStore } from "../stores/api";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
const stepsComponents = {
|
const stepsComponents = {
|
||||||
Intro,
|
Intro,
|
||||||
|
|
@ -47,6 +49,9 @@ function changeStep(stepName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setInitialStep() {
|
function setInitialStep() {
|
||||||
|
if (useRoute().query.step === "images") {
|
||||||
|
return "Images";
|
||||||
|
}
|
||||||
const hasPDF = page.value.content.pdf.length !== 0;
|
const hasPDF = page.value.content.pdf.length !== 0;
|
||||||
const hasImages =
|
const hasImages =
|
||||||
page.value.content.moodboard.length !== 0 ||
|
page.value.content.moodboard.length !== 0 ||
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue