diff --git a/src/EmailService.ts b/src/EmailService.ts index 8e417c4..6ee8563 100644 --- a/src/EmailService.ts +++ b/src/EmailService.ts @@ -25,7 +25,7 @@ export default class EmailService { pass: process.env.SMTP_PASSWORD, } } - console.log(config) + //console.log(config) return nodemailer.createTransport(config) } @@ -73,7 +73,7 @@ export default class EmailService { } else { this.nativeSend(config).then(res => { console.log('> A "' + templateName + '" email was sent') - resolve() + resolve(res) }).catch(err => { console.log('> A "' + templateName + '" email failed to be sent') console.error(err) diff --git a/src/controllers/AdminOrganizationController.ts b/src/controllers/AdminOrganizationController.ts index 7461d77..9fa06dc 100644 --- a/src/controllers/AdminOrganizationController.ts +++ b/src/controllers/AdminOrganizationController.ts @@ -19,6 +19,8 @@ export default class AdminOrganizationController { } static import(req: express.Request, res: express.Response) { + // first column is always name + // second column is always email const data = req.body.csv res.json({ success: true, @@ -69,8 +71,8 @@ export default class AdminOrganizationController { .then(data => { // generate extra slugs let extra: any = {} - if (req.body.name !== undefined) { - let slug = slugify(req.body.name) + if (req.body.adminName !== undefined) { + let slug = slugify(req.body.adminName) // only add this slug if the proposed slug is not found in the list of current slug let currentSlugs: string[] = [] if (data !== null && Array.isArray(data.get('slugs'))) { @@ -164,6 +166,22 @@ export default class AdminOrganizationController { const publishedVersion: any = data.get('publishedVersion') const proposedVersion: any = data.get('proposedVersion') + // generate extra slugs + // in case of a change by the organization it self, we need to keep up to date the slug + + let extra: any = {} + let slug = slugify(proposedVersion.name) + // only add this slug if the proposed slug is not found in the list of current slug + let currentSlugs: string[] = [] + if (Array.isArray(data.get('slugs'))) { + currentSlugs = data.get('slugs') + } + if (currentSlugs.filter(s => s === slug).length === 0) { + extra.slugs = currentSlugs.concat([slug]) + } + extra.adminName = proposedVersion.name + extra.email = proposedVersion.contacts.email + /** * Clean all the unused media from the publishedVersion */ @@ -203,6 +221,7 @@ export default class AdminOrganizationController { */ Organization.updateOne({ _id: req.params.id }, { + ...extra, publishedVersion: data.get('proposedVersion'), rejectionDescription: '', validationState: 'published', diff --git a/src/controllers/DefaultController.ts b/src/controllers/DefaultController.ts index 5da6492..c942077 100644 --- a/src/controllers/DefaultController.ts +++ b/src/controllers/DefaultController.ts @@ -59,15 +59,17 @@ export default class DefaultController { static async sendEmail(req: express.Request, res: express.Response) { // create reusable transporter object using the default SMTP transport - EmailService.getTransporter().sendMail({ - from: '"Some Sender" ', - to: "spamfree@matthieubessat.fr", - subject: "Hello ✔", - text: "Hello world? Comment va tu Earum facilis libero excepturi sunt fuga eveniet autem. Illo odit quae aperiam et praesentium. Error dignissimos atque omnis. Ea iste in doloribus praesentium corrupti. Ut consequatur eius eveniet quia aut. Nam a rerum quis. Repudiandae sit nobis esse. Eaque ipsum qui enim. Expedita laudantium officia omnis maxime. Odio exercitationem recusandae quis consequatur voluptatum.", - html: "

Hello world? Comment va tu Earum facilis libero excepturi sunt fuga eveniet autem. Illo odit quae aperiam et praesentium. Error dignissimos atque omnis. Ea iste in doloribus praesentium corrupti. Ut consequatur eius eveniet quia aut. Nam a rerum quis. Repudiandae sit nobis esse. Eaque ipsum qui enim. Expedita laudantium officia omnis maxime. Odio exercitationem recusandae quis consequatur voluptatum.

", - }).then(info => { - console.log("Message sent: %s", info.messageId); - console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info)); + EmailService.send( + 'matthieu.bessat.27@gmail.com', + "Email de test", + "token", + { + adminName: "Assos de test", + token: "tokendetest", + link: EmailService.getWebUiBaseUrl() + '/delegate?delegateToken=tokendetest' + } + ).then(info => { + console.log(info) }).catch(err => { console.error(err) }) diff --git a/src/controllers/PublicController.ts b/src/controllers/PublicController.ts index a4c03a5..570ae6a 100644 --- a/src/controllers/PublicController.ts +++ b/src/controllers/PublicController.ts @@ -22,6 +22,7 @@ export default class PublicController { // }) Tag.find().then(tags => { let isProposed = Utils.isStrUsable(req.query, 'only') + // @ts-ignore if (isProposed && !mongoose.Types.ObjectId.isValid(req.query.only)) { return ErrorController.handleServerError({ stack: 'Invalid object id in only query param'}, req, res, []) } @@ -105,10 +106,19 @@ export default class PublicController { return media }) } + version.cutDescription = Utils.isStrUsable(version, 'descriptionLong') && version.descriptionLong.length > 200 + // if (version.cutDescription) { + // version.descriptionFirstHalf = version.descriptionLong.substr(0, 200) // not gonna lie + // version.descriptionSecondHalf = version.descriptionLong.substr(200) + // } + let hour = lastPublished.toLocaleTimeString('fr-FR', { timezone: '+2' }) + if (hour.charAt(1) === ':') { + hour = '0' + hour + } res.render('organization.twig', { layout: 'standalone', data: version, - lastPublished: lastPublished.toLocaleDateString('fr-FR') + ' ' + lastPublished.toLocaleTimeString('fr-FR', { timezone: '+2' }).substr(0, 5), + lastPublished: lastPublished.toLocaleDateString('fr-FR') + ' ' + hour.substr(0, 5), isProposed, id: org.get('_id') }) diff --git a/src/models/Organization.ts b/src/models/Organization.ts index 348c486..f45487a 100644 --- a/src/models/Organization.ts +++ b/src/models/Organization.ts @@ -58,7 +58,13 @@ const OrganizationVersion = { address: { type: String }, person: { type: String }, email: { type: String }, - phone: { type: String } + phone: { type: String }, + peoples: [{ + name: { type: String }, + email: { type: String }, + phone: { type: String }, + role: { type: String } + }] }, schedule: [{ name: { type: String, required: true }, diff --git a/static/assets/home.css b/static/assets/home.css index ae7f2ba..d40109d 100644 --- a/static/assets/home.css +++ b/static/assets/home.css @@ -181,15 +181,16 @@ margin-bottom: 1em; box-shadow: 0 0 8px 0px rgba(0,0,0,0.1); transition: all 0.2s; - height: 12em; overflow: hidden; + text-decoration: none; } .card:hover { + text-decoration: none; transform: scale(1.02); } -.card-image { +.card-image-container { border-right: 1px solid #C4C4C4; display: flex; @@ -199,8 +200,12 @@ padding: 1em; } -.card-image img { +.card-image { + height: 12em; width: 12em; + + background-position: center; + background-size: cover; } .card-content { @@ -332,9 +337,13 @@ .card { display: block; } - .card-image { + .card-image-container { + padding: 0; + margin: 0; border-right: 0; border-bottom: 1px solid #C4C4C4; - margin: 0; + } + .card-content { + width: auto; } } diff --git a/static/assets/img/favicon-16x16.png b/static/assets/img/favicon-16x16.png new file mode 100755 index 0000000..3f77dc2 Binary files /dev/null and b/static/assets/img/favicon-16x16.png differ diff --git a/static/assets/img/favicon-32x32.png b/static/assets/img/favicon-32x32.png new file mode 100755 index 0000000..3f77dc2 Binary files /dev/null and b/static/assets/img/favicon-32x32.png differ diff --git a/static/assets/js/home.js b/static/assets/js/home.js index 6917ae0..46c9e09 100644 --- a/static/assets/js/home.js +++ b/static/assets/js/home.js @@ -15,12 +15,12 @@ navEnabler.onclick = async () => { // open the menu oldNavText = navEnablerText.textContent navEnablerText.textContent = "Minimiser le menu" - navEnablerIcon.style.transform = "rotate(0deg)" + navEnablerIcon.style.transform = "rotate(90eg)" navContent.style.maxHeight = navContent.scrollHeight + "px" } else { // close the menu navEnablerText.textContent = oldNavText - navEnablerIcon.style.transform = "rotate(-90deg)" + navEnablerIcon.style.transform = "rotate(0deg)" navContent.style.maxHeight = null } navOpened = !navOpened @@ -82,12 +82,12 @@ function setAttributes(node, attrs) { } function renderCard(organization) { - let card = createEl('card') + let card = createEl('card', 'a') // image - let image = createEl('card-image') - let imageTag = createEl(0, 'img') - imageTag.src = organization.thumbnail + let image = createEl('card-image-container') + let imageTag = createEl('card-image') + imageTag.style = `background-image: url('${organization.thumbnail}')` image.appendChild(imageTag) card.appendChild(image) @@ -117,14 +117,15 @@ function renderCard(organization) { let description = createEl('card-description') description.textContent = organization.description - //let link = createEl('card-link') - let aTag = createEl('card-link', 'a') - aTag.href = "/association/" + organization.slugs[organization.slugs.length - 1] + let goTo = "/association/" + organization.slugs[organization.slugs.length - 1] if (organization.isProposed) { - aTag.href += "?version=proposed" + goTo += "?version=proposed" } - aTag.textContent = "En savoir plus" - description.appendChild(aTag) + // let link = createEl('card-link') + // let aTag = createEl('card-link', 'a') + // aTag.href = + // aTag.textContent = "En savoir plus" + // description.appendChild(aTag) upperContent.appendChild(description) //link.appendChild(aTag) @@ -132,9 +133,11 @@ function renderCard(organization) { //content.appendChild(link) card.appendChild(content) - card.onclick = () => { - window.location = aTag.href - } + card.href = goTo + + // card.onclick = () => { + // window.location = goTo + // } return card } diff --git a/static/assets/js/organization.js b/static/assets/js/organization.js index b567f08..4ce721d 100644 --- a/static/assets/js/organization.js +++ b/static/assets/js/organization.js @@ -9,17 +9,43 @@ document.querySelectorAll('.schedule-category').forEach(node => { header.onclick = () => { if (!opened) { // open the table - icon.style.transform = "rotate(180deg)" + icon.style.transform = "rotate(0deg)" content.style.maxHeight = content.scrollHeight + "px" } else { // close the table - icon.style.transform = "rotate(0deg)" + icon.style.transform = "rotate(180deg)" content.style.maxHeight = null } opened = !opened } }) +/** + * Description + */ +let description = document.querySelector('.description-cutted') +let descriptionActions = document.querySelector('.description-actions-container') +let descriptionOpened = false +let defaultMaxHeight = "" +if (description !== null) { + let btn = document.querySelector('.description-btn') + btn.onclick = () => { + if (!descriptionOpened) { + // open the full description + descriptionActions.className = descriptionActions.className.replace(' closed', '') + defaultMaxHeight = description.style.maxHeight + description.style.maxHeight = description.scrollHeight + "px" + btn.textContent = "Fermer la description" + } else { + // initial max Height + descriptionActions.className += ' closed' + description.style.maxHeight = defaultMaxHeight + btn.textContent = "Ouvrir la description" + } + descriptionOpened = !descriptionOpened + } +} + /** * Gallery modal to view media in large */ @@ -70,8 +96,22 @@ let openModal = (url, isVideo) => { //document.body.style.height = '100vh' document.body.style.overflow = 'hidden' document.body.style.touchAction = 'none' + + setTimeout(() => { + + const outsideClickListener = event => { + if (!mediaModalContent.contains(event.target) && isVisible(mediaModalContent)) { + closeModal() + document.removeEventListener('click', outsideClickListener) + } + } + document.addEventListener('click', outsideClickListener) + + }, 100) } +const isVisible = elem => !!elem && !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ) + let closeModal = () => { mediaModal.style.visibility = 'hidden' mediaModal.style.opacity = 0 diff --git a/static/assets/main.css b/static/assets/main.css index 9763087..567b1e9 100644 --- a/static/assets/main.css +++ b/static/assets/main.css @@ -53,6 +53,19 @@ body { color: white; } +.btn { + padding: .5em 1em; + color: white; + border-radius: 7px; + background: #2c3e50; + border: 0; +} + +.btn:focus { + outline: 0; + opacity: 0.8; +} + @media (max-width: 1600px) { .container { width: 70%; diff --git a/static/assets/organization.css b/static/assets/organization.css index 48aa34f..7cddf8d 100644 --- a/static/assets/organization.css +++ b/static/assets/organization.css @@ -57,7 +57,7 @@ .cover { height: 13em; margin-top: -13em; - background-color: rgba(230, 126, 34, 0.78); + background-color: rgba(230, 126, 34, 0.4); background-size: cover; } @@ -294,7 +294,7 @@ section { text-align: justify; margin: 0 auto; width: 80%; - margin-top: 1.5em; + margin-top: 1em; margin-bottom: .5em; } @@ -332,16 +332,37 @@ section { padding-left: 1em; } +.description-cutted { + max-height: 13em; + + overflow: hidden; + transition: max-height 0.1s ease-out; + +} + +.description-actions-container { + display: flex; + justify-content: center; + align-items: center; + margin-top: 1em; +} + +.description-actions-container.closed { + box-shadow: 0px -16px 16px -3px rgb(255, 255, 255); + background: rgba(255,255,255,0.8); + position: relative; + top: -62px; + + height: 62px; + margin-bottom: -62px; +} + /* ***************************************************************************** * SCHEDULE ********************************************************************************/ -.schedule { - -} - .schedule-category { margin-bottom: 1em; } @@ -357,13 +378,13 @@ section { } .schedule-category-collapse-icon { + transform: rotate(180deg); color: #B12008; width: 1.5em; transition: all 0.1s ease-out; } .schedule-category-table { - max-height: 0; overflow: hidden; transition: max-height 0.1s ease-out; @@ -376,7 +397,7 @@ section { margin-left: 2em; margin-top: 1em; margin-bottom: 1em; - margin-right: 40em; + margin-right: 20em; padding: 1em 2em 1em 2em; } @@ -395,6 +416,14 @@ section { margin-bottom: 0; } +.schedule-category-hours { + color: #2c3e50; +} + +.schedule-category-hours .spearator { + color: #bdc3c7; +} + /* ***************************************************************************** * PRICING @@ -450,7 +479,7 @@ section { ********************************************************************************/ -.contact { +.org-container { margin: 0 auto; width: 70%; } @@ -541,13 +570,15 @@ section { .mentions { display: flex; justify-content: center; - width: 100%; + padding-left: 1em; + padding-right: 1em; flex-direction: column; text-align: center; color: #d35400; - margin-top: 2em; - margin-bottom: .5em; + margin-top: 1em; + margin-bottom: 1em; } + .mentions div { margin-bottom: .5em; } @@ -589,17 +620,17 @@ RESPONSIVE @media (max-width: 900px) { .cover-background { - height: 30em; + height: 23em; width: 100%; } .cover { - height: 30em; - margin-top: -30em; + height: 23em; + margin-top: -23em; } .cover-content { - height: 30em; + height: 23em; flex-direction: column; justify-content: center; @@ -628,6 +659,10 @@ RESPONSIVE } /* Mosaic level 2 */ + .mosaic-2 { + grid-template-rows: 1fr 1fr; + } + .mosaic-2, .mosaic-3 { grid-template-columns: 1fr; } @@ -684,7 +719,7 @@ RESPONSIVE margin-bottom: 1em; } - .contact { + .org-container { width: 100%; } @@ -720,4 +755,7 @@ RESPONSIVE .media-modal { width: 90%; } + .description { + width: 95%; + } } \ No newline at end of file diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..11e5d61 Binary files /dev/null and b/static/favicon.ico differ diff --git a/views/base.twig b/views/base.twig index ac13e88..12ca714 100644 --- a/views/base.twig +++ b/views/base.twig @@ -35,7 +35,7 @@ Github: https://github.com/lefuturiste class="header-sub-title"> Espace Condorcet Centre Social -

Forum des associations

+

Forum des associations 2020

Cette année nous vous invitons à découvrir le forum virtuel des associations.
diff --git a/views/emails/test.twig b/views/emails/test.twig new file mode 100644 index 0000000..d183fd0 --- /dev/null +++ b/views/emails/test.twig @@ -0,0 +1,7 @@ +

+This is a test +

+ +

+Date: {{ date }} +

\ No newline at end of file diff --git a/views/organization.twig b/views/organization.twig index 26da092..4d5feac 100644 --- a/views/organization.twig +++ b/views/organization.twig @@ -73,8 +73,17 @@
- {% if data.descriptionLong is not null and data.descriptionLong|length > 7 %} + {% if data.descriptionLong is not null and data.descriptionLong|length > 7 and not data.cutDescription %} {{ data.descriptionLong|raw }} + {% elseif data.cutDescription %} +
+ {{ data.descriptionLong }} +
+
+ +
{% else %} {{ data.descriptionShort }} {% endif %} @@ -88,8 +97,9 @@

Crénaux

-
- {% for item in data.schedule %} +
+ {% for item in data.schedule %} + {% if item.when|length > 0 %}
@@ -120,6 +130,7 @@
+ {% endif %} {% endfor %}
@@ -155,7 +166,7 @@

Contact

-
+
{% if data.contacts.person|length > 0 %}