coyotte508 HF staff commited on
Commit
9b30f5f
1 Parent(s): 34660c6

✨ Contact page

Browse files
package.json CHANGED
@@ -39,7 +39,9 @@
39
  },
40
  "type": "module",
41
  "dependencies": {
 
42
  "lodash": "^4.17.21",
 
43
  "marked": "^4.2.2",
44
  "mongodb": "^4.11.0"
45
  }
 
39
  },
40
  "type": "module",
41
  "dependencies": {
42
+ "form-data": "^4.0.0",
43
  "lodash": "^4.17.21",
44
+ "mailgun.js": "^8.0.2",
45
  "marked": "^4.2.2",
46
  "mongodb": "^4.11.0"
47
  }
pnpm-lock.yaml CHANGED
@@ -15,7 +15,9 @@ specifiers:
15
  eslint: ^8.16.0
16
  eslint-config-prettier: ^8.3.0
17
  eslint-plugin-svelte3: ^4.0.0
 
18
  lodash: ^4.17.21
 
19
  marked: ^4.2.2
20
  mongodb: ^4.11.0
21
  prettier: ^2.6.2
@@ -30,7 +32,9 @@ specifiers:
30
  vite: ^3.1.0
31
 
32
  dependencies:
 
33
  lodash: 4.17.21
 
34
  marked: 4.2.2
35
  mongodb: 4.11.0
36
 
@@ -38,7 +42,7 @@ devDependencies:
38
  '@iconify-json/ant-design': 1.1.3
39
  '@iconify-json/il': 1.1.2
40
  '@sveltejs/adapter-node': 1.0.0-next.100
41
- '@sveltejs/kit': 1.0.0-next.538_svelte@3.52.0+vite@3.2.2
42
  '@types/lodash': 4.14.188
43
  '@types/marked': 4.0.7
44
  '@typescript-eslint/eslint-plugin': 5.42.0_6xw5wg2354iw4zujk2f3vyfrzu
@@ -1072,8 +1076,8 @@ packages:
1072
  rollup: 2.79.1
1073
  dev: true
1074
 
1075
- /@sveltejs/kit/1.0.0-next.538_svelte@3.52.0+vite@3.2.2:
1076
- resolution: {integrity: sha512-NRu6+j1Lc0daE2OirlbDCbT/yMf5l5nFln2o1asMA3HL7A244SG+uGGFea4DZ1bdetZ3IhO5xa1MWIGY5Ybb3g==}
1077
  engines: {node: '>=16.14'}
1078
  hasBin: true
1079
  requiresBuild: true
@@ -1514,10 +1518,27 @@ packages:
1514
  engines: {node: '>=8'}
1515
  dev: true
1516
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1517
  /balanced-match/1.0.2:
1518
  resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
1519
  dev: true
1520
 
 
 
 
 
1521
  /base64-js/1.5.1:
1522
  resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
1523
  dev: false
@@ -1630,6 +1651,13 @@ packages:
1630
  resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
1631
  dev: true
1632
 
 
 
 
 
 
 
 
1633
  /commondir/1.0.1:
1634
  resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
1635
  dev: true
@@ -1689,6 +1717,11 @@ packages:
1689
  resolution: {integrity: sha512-pOFYRTIhoKujrmbTRhcW5lYQLBXw/dlTwfI8IguF1QCDJOcJzNH1w+YFjxqy6BAuJrClTy6MUE8q+oKJ2FLsIw==}
1690
  dev: true
1691
 
 
 
 
 
 
1692
  /denque/2.1.0:
1693
  resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
1694
  engines: {node: '>=0.10'}
@@ -2175,6 +2208,25 @@ packages:
2175
  resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
2176
  dev: true
2177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2178
  /fs.realpath/1.0.0:
2179
  resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
2180
  dev: true
@@ -2470,6 +2522,16 @@ packages:
2470
  sourcemap-codec: 1.4.8
2471
  dev: true
2472
 
 
 
 
 
 
 
 
 
 
 
2473
  /marked/4.2.2:
2474
  resolution: {integrity: sha512-JjBTFTAvuTgANXx82a5vzK9JLSMoV6V3LBVn4Uhdso6t7vXrGx7g1Cd2r6NYSsxrYbQGFCMqBDhFHyK5q2UvcQ==}
2475
  engines: {node: '>= 12'}
@@ -2502,6 +2564,18 @@ packages:
2502
  picomatch: 2.3.1
2503
  dev: true
2504
 
 
 
 
 
 
 
 
 
 
 
 
 
2505
  /mime/3.0.0:
2506
  resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
2507
  engines: {node: '>=10.0.0'}
@@ -3171,6 +3245,10 @@ packages:
3171
  punycode: 2.1.1
3172
  dev: true
3173
 
 
 
 
 
3174
  /uuid/8.3.2:
3175
  resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
3176
  hasBin: true
 
15
  eslint: ^8.16.0
16
  eslint-config-prettier: ^8.3.0
17
  eslint-plugin-svelte3: ^4.0.0
18
+ form-data: ^4.0.0
19
  lodash: ^4.17.21
20
+ mailgun.js: ^8.0.2
21
  marked: ^4.2.2
22
  mongodb: ^4.11.0
23
  prettier: ^2.6.2
 
32
  vite: ^3.1.0
33
 
34
  dependencies:
35
+ form-data: 4.0.0
36
  lodash: 4.17.21
37
+ mailgun.js: 8.0.2
38
  marked: 4.2.2
39
  mongodb: 4.11.0
40
 
 
42
  '@iconify-json/ant-design': 1.1.3
43
  '@iconify-json/il': 1.1.2
44
  '@sveltejs/adapter-node': 1.0.0-next.100
45
+ '@sveltejs/kit': 1.0.0-next.542_svelte@3.52.0+vite@3.2.2
46
  '@types/lodash': 4.14.188
47
  '@types/marked': 4.0.7
48
  '@typescript-eslint/eslint-plugin': 5.42.0_6xw5wg2354iw4zujk2f3vyfrzu
 
1076
  rollup: 2.79.1
1077
  dev: true
1078
 
1079
+ /@sveltejs/kit/1.0.0-next.542_svelte@3.52.0+vite@3.2.2:
1080
+ resolution: {integrity: sha512-0YaNfrNsCwgCYuYEEKUF7G/QAkeGNJRlAFnPa9WTG2kRQPqlfUKOJlAniRHVG08ARdfNJgBSootWFvAUsKSoYA==}
1081
  engines: {node: '>=16.14'}
1082
  hasBin: true
1083
  requiresBuild: true
 
1518
  engines: {node: '>=8'}
1519
  dev: true
1520
 
1521
+ /asynckit/0.4.0:
1522
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
1523
+ dev: false
1524
+
1525
+ /axios/0.27.2:
1526
+ resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
1527
+ dependencies:
1528
+ follow-redirects: 1.15.2
1529
+ form-data: 4.0.0
1530
+ transitivePeerDependencies:
1531
+ - debug
1532
+ dev: false
1533
+
1534
  /balanced-match/1.0.2:
1535
  resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
1536
  dev: true
1537
 
1538
+ /base-64/1.0.0:
1539
+ resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==}
1540
+ dev: false
1541
+
1542
  /base64-js/1.5.1:
1543
  resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
1544
  dev: false
 
1651
  resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
1652
  dev: true
1653
 
1654
+ /combined-stream/1.0.8:
1655
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
1656
+ engines: {node: '>= 0.8'}
1657
+ dependencies:
1658
+ delayed-stream: 1.0.0
1659
+ dev: false
1660
+
1661
  /commondir/1.0.1:
1662
  resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
1663
  dev: true
 
1717
  resolution: {integrity: sha512-pOFYRTIhoKujrmbTRhcW5lYQLBXw/dlTwfI8IguF1QCDJOcJzNH1w+YFjxqy6BAuJrClTy6MUE8q+oKJ2FLsIw==}
1718
  dev: true
1719
 
1720
+ /delayed-stream/1.0.0:
1721
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
1722
+ engines: {node: '>=0.4.0'}
1723
+ dev: false
1724
+
1725
  /denque/2.1.0:
1726
  resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
1727
  engines: {node: '>=0.10'}
 
2208
  resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
2209
  dev: true
2210
 
2211
+ /follow-redirects/1.15.2:
2212
+ resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
2213
+ engines: {node: '>=4.0'}
2214
+ peerDependencies:
2215
+ debug: '*'
2216
+ peerDependenciesMeta:
2217
+ debug:
2218
+ optional: true
2219
+ dev: false
2220
+
2221
+ /form-data/4.0.0:
2222
+ resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
2223
+ engines: {node: '>= 6'}
2224
+ dependencies:
2225
+ asynckit: 0.4.0
2226
+ combined-stream: 1.0.8
2227
+ mime-types: 2.1.35
2228
+ dev: false
2229
+
2230
  /fs.realpath/1.0.0:
2231
  resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
2232
  dev: true
 
2522
  sourcemap-codec: 1.4.8
2523
  dev: true
2524
 
2525
+ /mailgun.js/8.0.2:
2526
+ resolution: {integrity: sha512-s0esDPrHlo72rLylEj61akLO49HvUltmjKIj/lrbY89kWcL/lcPy23yh4ifFkWTuiBO6oHVqXwzfQI3lhSvK9A==}
2527
+ dependencies:
2528
+ axios: 0.27.2
2529
+ base-64: 1.0.0
2530
+ url-join: 4.0.1
2531
+ transitivePeerDependencies:
2532
+ - debug
2533
+ dev: false
2534
+
2535
  /marked/4.2.2:
2536
  resolution: {integrity: sha512-JjBTFTAvuTgANXx82a5vzK9JLSMoV6V3LBVn4Uhdso6t7vXrGx7g1Cd2r6NYSsxrYbQGFCMqBDhFHyK5q2UvcQ==}
2537
  engines: {node: '>= 12'}
 
2564
  picomatch: 2.3.1
2565
  dev: true
2566
 
2567
+ /mime-db/1.52.0:
2568
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
2569
+ engines: {node: '>= 0.6'}
2570
+ dev: false
2571
+
2572
+ /mime-types/2.1.35:
2573
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
2574
+ engines: {node: '>= 0.6'}
2575
+ dependencies:
2576
+ mime-db: 1.52.0
2577
+ dev: false
2578
+
2579
  /mime/3.0.0:
2580
  resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
2581
  engines: {node: '>=10.0.0'}
 
3245
  punycode: 2.1.1
3246
  dev: true
3247
 
3248
+ /url-join/4.0.1:
3249
+ resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==}
3250
+ dev: false
3251
+
3252
  /uuid/8.3.2:
3253
  resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
3254
  hasBin: true
src/lib/server/mail.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { MAILGUN_API_KEY } from '$env/static/private';
2
+ import Mailgun from 'mailgun.js';
3
+ import formData from 'form-data';
4
+
5
+ const mailgun = new Mailgun(formData);
6
+
7
+ export const mg = mailgun.client({
8
+ username: 'api',
9
+ key: MAILGUN_API_KEY,
10
+ url: 'https://api.eu.mailgun.net'
11
+ });
src/routes/contact/+page.server.ts ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { mg } from '$lib/server/mail';
2
+ import type { Actions } from './$types';
3
+
4
+ export const actions: Actions = {
5
+ default: async (event) => {
6
+ const body = await event.request.formData();
7
+ if (
8
+ !body.get('email') ||
9
+ !body.get('message') ||
10
+ !body.get('firstName') ||
11
+ !body.get('lastName')
12
+ ) {
13
+ return {
14
+ status: 400,
15
+ body: {
16
+ error: 'Veuillez remplir tous les champs'
17
+ }
18
+ };
19
+ }
20
+
21
+ const firstName = body.get('firstName').toString().trim();
22
+ const lastName = body.get('lastName').toString().trim();
23
+ const message = body.get('message').toString().trim();
24
+ const email = body.get('email').toString().trim();
25
+
26
+ await mg.messages.create('mails.bergereenchantee.fr', {
27
+ from: 'Formulaire de contact <contact@mails.bergereenchantee.fr>',
28
+ to: ['contact@bergereenchantee.fr'],
29
+ subject: `Message de ${firstName} ${lastName}`,
30
+ 'h:Reply-To': email,
31
+ text: message,
32
+ 'o:tag': 'contact'
33
+ });
34
+
35
+ return { success: true };
36
+ }
37
+ };
src/routes/contact/+page.svelte ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { ContactPage } from '$lib/types/Page';
3
+ import Container from '$lib/components/Container.svelte';
4
+ import { marked } from 'marked';
5
+ import Picture from '$lib/components/Picture.svelte';
6
+ import type { ActionData, PageData } from './$types';
7
+ import { enhance } from '$app/forms';
8
+
9
+ export let data: PageData;
10
+
11
+ const pageData: ContactPage = data.pageData as ContactPage;
12
+ const pictures = data.pictures;
13
+
14
+ export let form: ActionData;
15
+ </script>
16
+
17
+ <Container class="mb-6">
18
+ <section class="relative lg:h-xl mt-12 flex">
19
+ <img
20
+ src="/triangles.svg"
21
+ alt="Triangles"
22
+ class="pointer-events-none select-none absolute hidden lg:block h-5/6"
23
+ style="left: 50%; top: 50%; transform: translate(-50%, -50%) scaleX(-1); z-index: -1"
24
+ />
25
+ <Picture
26
+ picture={pictures.find((p) => p._id === pageData.pictures['photo-garde'])}
27
+ sizes="(max-width: 1200px) 50vw, 600px"
28
+ grow
29
+ basis-0
30
+ hidden
31
+ class="rounded-3xl h-full object-cover w-3/6 lg:block"
32
+ />
33
+ <div class="lg:w-3/6 h-full flex flex-col justify-evenly lg:pl-12">
34
+ <h2 class="text-oxford text-7xl mb-7 lg:mb-0" style="mix-blend-mode: color-burn;">Contact</h2>
35
+ <ul class="text-oxford">
36
+ <li class="flex items-center">
37
+ <div class="i-ant-design-phone-outlined inline-block mr-2" />
38
+ <a rel="external" href="tel:+33774521115">07 74 52 11 15</a>
39
+ </li>
40
+ <li class="flex items-center mt-2">
41
+ <div class="i-ant-design-mail-outlined inline-block mr-2" />
42
+ <a rel="external" href="mailto:contact@bergereenchantee.fr">contact@bergereenchantee.fr</a
43
+ >
44
+ </li>
45
+ <li class="flex mt-2">
46
+ <div class="i-ant-design-clock-circle-outlined inline-block mr-2 lg:mt-1" />
47
+ le lundi mardi jeudi vendredi de 9h à 17h30 et le mercredi de 9h à 12h
48
+ </li>
49
+ </ul>
50
+ </div>
51
+ </section>
52
+ <div class="pt-3">
53
+ {@html marked(pageData.text.description)}
54
+ </div>
55
+
56
+ {#if form?.success}
57
+ <div class="border border-blue-500 bg-blue-300 rounded-lg pa-2">
58
+ Votre message a bien été envoyé. <br /><br /> Daphné vous répondra rapidement.
59
+ </div>
60
+ {:else}
61
+ <form method="post" class="text-oxford font-semibold text-lg" use:enhance>
62
+ <div class="mt-4">
63
+ <label for="lastName" class="block">Nom</label>
64
+ <input
65
+ type="text"
66
+ name="lastName"
67
+ id="lastName"
68
+ placeholder="Nom"
69
+ class="input box-border"
70
+ style="max-width: 100% !important"
71
+ required
72
+ />
73
+ </div>
74
+
75
+ <div class="mt-4">
76
+ <label for="firstName" class="block">Prénom</label>
77
+ <input
78
+ type="text"
79
+ name="firstName"
80
+ id="firstName"
81
+ placeholder="Prénom"
82
+ class="input box-border"
83
+ style="max-width: 100% !important"
84
+ required
85
+ />
86
+ </div>
87
+
88
+ <div class="mt-4">
89
+ <label for="email" class="block">Mail</label>
90
+ <input
91
+ type="email"
92
+ name="email"
93
+ id="email"
94
+ placeholder="Adresse mail"
95
+ class="input box-border"
96
+ style="max-width: 100% !important"
97
+ required
98
+ />
99
+ </div>
100
+
101
+ <div class="mt-4">
102
+ <label for="message" class="block">Message</label>
103
+ <textarea
104
+ name="message"
105
+ id="message"
106
+ cols="30"
107
+ rows="5"
108
+ class="input box-border"
109
+ style="max-width: 100% !important"
110
+ placeholder="Votre message"
111
+ required
112
+ />
113
+ </div>
114
+
115
+ <div class="w-full flex mt-4">
116
+ <button type="submit" class="btn ml-auto cursor-pointer"> Envoyer </button>
117
+ </div>
118
+ </form>
119
+ {/if}
120
+ </Container>