parent
fd79d99444
commit
b5af543a0e
@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": ["plugin:cypress/recommended", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
import { defineConfig } from 'cypress';
|
||||
import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset';
|
||||
|
||||
export default defineConfig({
|
||||
e2e: nxE2EPreset(__dirname),
|
||||
});
|
||||
@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "vendors-e2e",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/vendors-e2e/src",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"e2e": {
|
||||
"executor": "@nrwl/cypress:cypress",
|
||||
"options": {
|
||||
"cypressConfig": "apps/vendors-e2e/cypress.config.ts",
|
||||
"devServerTarget": "vendors:serve:development",
|
||||
"testingType": "e2e"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "vendors:serve:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["apps/vendors-e2e/**/*.{js,ts}"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"implicitDependencies": ["vendors"]
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
import { getGreeting } from '../support/app.po';
|
||||
|
||||
describe('vendors', () => {
|
||||
beforeEach(() => cy.visit('/'));
|
||||
|
||||
it('should display welcome message', () => {
|
||||
// Custom command example, see `../support/commands.ts` file
|
||||
cy.login('my-email@something.com', 'myPassword');
|
||||
|
||||
// Function helper example, see `../support/app.po.ts` file
|
||||
getGreeting().contains('Welcome vendors');
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io"
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
export const getGreeting = () => cy.get('h1');
|
||||
@ -0,0 +1,33 @@
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
declare namespace Cypress {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface Chainable<Subject> {
|
||||
login(email: string, password: string): void;
|
||||
}
|
||||
}
|
||||
//
|
||||
// -- This is a parent command --
|
||||
Cypress.Commands.add('login', (email, password) => {
|
||||
console.log('Custom command example: Login', email, password);
|
||||
});
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
@ -0,0 +1,17 @@
|
||||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"sourceMap": false,
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"allowJs": true,
|
||||
"types": ["cypress", "node"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.js", "cypress.config.ts"]
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
NX_STRAPI_URL_API=http://localhost:1337/api
|
||||
NX_STRAPI_URL=http://localhost:1337
|
||||
NEXTAUTH_URL=http://localhost:4300
|
||||
@ -0,0 +1,31 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:@nrwl/nx/react-typescript",
|
||||
"next",
|
||||
"next/core-web-vitals",
|
||||
"../../.eslintrc.json"
|
||||
],
|
||||
"ignorePatterns": ["!**/*", ".next/**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {
|
||||
"@next/next/no-html-link-for-pages": ["error", "apps/vendors/pages"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
],
|
||||
"rules": {
|
||||
"@next/next/no-html-link-for-pages": "off"
|
||||
},
|
||||
"env": {
|
||||
"jest": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Replace this with your own classes
|
||||
*
|
||||
* e.g.
|
||||
* .container {
|
||||
* }
|
||||
*/
|
||||
.app-container {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
|
||||
.app-content {
|
||||
position: relative;
|
||||
padding-top: 58px;
|
||||
min-height: calc(100vh - 189px);
|
||||
}
|
||||
}
|
||||
|
||||
.without-headers {
|
||||
padding-top: 0;
|
||||
|
||||
.app-content {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.without-footer {
|
||||
padding-top: 0;
|
||||
|
||||
.app-content {
|
||||
min-height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 453px) {
|
||||
.app-container:not(.without-footer) {
|
||||
.app-content {
|
||||
min-height: calc(100vh - 169px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.app-container:not(.without-footer) {
|
||||
.app-content {
|
||||
min-height: calc(100vh - 133px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.app-container:not(.without-headers) {
|
||||
.app-content {
|
||||
padding-top: 128px;
|
||||
}
|
||||
}
|
||||
.app-container:not(.without-footer) {
|
||||
.app-content {
|
||||
min-height: calc(100vh - 165px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.app-container:not(.without-footer) {
|
||||
.app-content {
|
||||
padding-top: 131px;
|
||||
min-height: calc(100vh - 181px);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
|
||||
import styles from './layout.module.scss';
|
||||
|
||||
export function Layout({
|
||||
showHeaders = true,
|
||||
showFooter = true,
|
||||
menuHeader = [],
|
||||
menuFooter = [],
|
||||
children = null,
|
||||
className = '',
|
||||
headerTransparent = false
|
||||
}) {
|
||||
|
||||
const renderHeaders = () => {
|
||||
if (showHeaders) {
|
||||
return (<p>header </p>)
|
||||
} else {
|
||||
return ('');
|
||||
}
|
||||
}
|
||||
const renderFooters = () => {
|
||||
if (showFooter) {
|
||||
return (<p>footer </p>)
|
||||
} else {
|
||||
return ('');
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderHeaders()}
|
||||
<div
|
||||
className={'dark:bg-gray-900 bg-gray-50 ' + styles['app-container'] + ' ' + (showHeaders ? '' : styles['without-headers']) + ' ' + (showFooter ? '' : styles['without-footer']) + ' ' + className}>
|
||||
<div className={styles['app-content'] + " w-full mx-auto"}>
|
||||
{children}
|
||||
</div>
|
||||
{renderFooters()}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Layout;
|
||||
@ -0,0 +1,50 @@
|
||||
export const config = {
|
||||
env: {
|
||||
STRAPI_URL_API: process.env.NX_STRAPI_URL_API,
|
||||
STRAPI_URL: process.env.NX_STRAPI_URL,
|
||||
NEXTAUTH_SECRET: process.env.NX_NEXTAUTH_SECRET,
|
||||
NEXTAUTH_URL: process.env.NX_NEXTAUTH_URL,
|
||||
},
|
||||
mainApiEndpoint: 'https://conduit.productionready.io/api'
|
||||
}
|
||||
|
||||
export const theme = {
|
||||
colors: {
|
||||
primary: '#3b5998',
|
||||
secondary: '#8b9dc3',
|
||||
gray: '#f7f7f7'
|
||||
},
|
||||
width: {
|
||||
xl: 1200,
|
||||
l: 900,
|
||||
m: 750,
|
||||
s: 400
|
||||
}
|
||||
}
|
||||
|
||||
export const siteConfig = {
|
||||
siteTitle: 'Conduit', // Navigation and Site Title
|
||||
siteUrl: process.env.ROOT_URL || 'https://next.org', // Domain of your site. No trailing slash!
|
||||
siteLanguage: 'fr', // Language Tag on <html> element
|
||||
siteLogo: '/logo.png', // Used for SEO and manifest, path to your image you placed in the 'static' folder
|
||||
siteDescription: 'Real world example of nextjs SSR',
|
||||
author: 'arrlancore', // Author for schemaORGJSONLD
|
||||
organization: 'Open Source Organization',
|
||||
|
||||
userTwitter: '@arrlancore', // Twitter Username
|
||||
ogSiteName: 'Dwiki Arlan', // Facebook Site Name
|
||||
ogLanguage: 'en_US',
|
||||
googleAnalyticsID: process.env.GOOGLE_ANALYTIC_ID || 'UA-XXX123-1',
|
||||
|
||||
// Manifest and Progress color
|
||||
themeColor: '#4147DC',
|
||||
backgroundColor: '#231C42',
|
||||
defaultUserAvatar: '',
|
||||
|
||||
// Social component
|
||||
twitter: 'https://twitter.com/arrlancore/',
|
||||
twitterHandle: '@arrlancore',
|
||||
github: 'https://github.com/arrlancore/',
|
||||
youtube: 'https://www.youtube.com/',
|
||||
rss: 'https://next.org/blog/rss.xml'
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
export const environment = {
|
||||
appUrl: 'http://localhost:4200',
|
||||
strapiUrl: 'http://localhost:1337',
|
||||
strapiApiUrl: 'http://localhost:1337/api',
|
||||
nextAuthSecret: "yBNW1wrb9CgOvEfbX6EQCvCDqiMkRBZP",
|
||||
meiliUrl: "http://127.0.0.1:7700",
|
||||
meiliApiKey: "f2e963e883cbacf6d4f63e792dc276491b8a866fb837f3fda37b8b78889a6851",
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
export const environment = {
|
||||
appUrl: 'http://localhost:4200',
|
||||
strapiUrl: 'https://admin.mecp.nasercloud.fr',
|
||||
strapiApiUrl: 'https://admin.mecp.nasercloud.fr/api',
|
||||
nextAuthSecret: "yBNW1wrb9CgOvEfbX6EQCvCDqiMkRBZP",
|
||||
meiliUrl: "https://ms-b6dafcb0b382-1943.fra.meilisearch.io",
|
||||
meiliApiKey: "0e9a9d027b9e6b2d98c9670e5030a8d1aa72cab911fd768d4ad02636ae673690",
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
export const environment = {
|
||||
appUrl: 'http://localhost:4200',
|
||||
strapiUrl: 'https://admin.mecp.nasercloud.fr',
|
||||
strapiApiUrl: 'https://admin.mecp.nasercloud.fr/api',
|
||||
nextAuthSecret: "yBNW1wrb9CgOvEfbX6EQCvCDqiMkRBZP",
|
||||
meiliUrl: "https://ms-b6dafcb0b382-1943.fra.meilisearch.io",
|
||||
meiliApiKey: "dda9e4a354839db9ae18c3722ae75422515c06525b3a841010928b5256f54e72",
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
export const environment = {
|
||||
appUrl: 'http://localhost:4200',
|
||||
strapiUrl: 'http://localhost:1337',
|
||||
strapiApiUrl: 'http://localhost:1337/api',
|
||||
nextAuthSecret: "yBNW1wrb9CgOvEfbX6EQCvCDqiMkRBZP",
|
||||
meiliUrl: "http://127.0.0.1:7700",
|
||||
meiliApiKey: "dda9e4a354839db9ae18c3722ae75422515c06525b3a841010928b5256f54e72",
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
declare module '*.svg' {
|
||||
const content: any;
|
||||
export const ReactComponent: any;
|
||||
export default content;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'vendors',
|
||||
preset: '../../jest.preset.js',
|
||||
transform: {
|
||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
|
||||
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/next/babel'] }],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/apps/vendors',
|
||||
};
|
||||
@ -0,0 +1,46 @@
|
||||
import axios from "axios";
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {environment} from "../environments/environment";
|
||||
import {config} from "../config";
|
||||
|
||||
export type Inputs = {
|
||||
email: string,
|
||||
username: string,
|
||||
password: string,
|
||||
passwordConfirmation: string,
|
||||
agreement: boolean,
|
||||
newsletter: boolean,
|
||||
}
|
||||
|
||||
export type LostPasswordInputs = {
|
||||
email: string;
|
||||
}
|
||||
|
||||
export type ResetPasswordInputs = {
|
||||
password: string,
|
||||
passwordConfirmation: string,
|
||||
code: string
|
||||
}
|
||||
|
||||
export const hasAvatar = (user) => {
|
||||
return !_.isNil(user.avatar);
|
||||
}
|
||||
|
||||
export const getBackendImg = (imageUrl: string) => {
|
||||
return `${environment.strapiUrl}${imageUrl}`;
|
||||
}
|
||||
|
||||
export const signUpRequest = async (inputs: Inputs) => {
|
||||
try {
|
||||
const registerResponse = await axios.post(`${environment.strapiApiUrl}/auth/local/register`, {
|
||||
email: inputs.email,
|
||||
password: inputs.password,
|
||||
username: inputs.username,
|
||||
newsletter: inputs.newsletter
|
||||
});
|
||||
return registerResponse.data;
|
||||
} catch (err) {
|
||||
return Promise.reject('Internal error');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
import axios from 'axios';
|
||||
import {signIn} from "next-auth/react";
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {config} from "../config";
|
||||
import {environment} from "../environments/environment";
|
||||
|
||||
export async function createJwtToken(email, password) {
|
||||
return await signIn('credentials', {
|
||||
redirect: false,
|
||||
email,
|
||||
password,
|
||||
});
|
||||
}
|
||||
|
||||
export async function signInStrapi({email, password}) {
|
||||
const res = await axios.post(`${environment.strapiApiUrl}/auth/local`, {
|
||||
identifier: email,
|
||||
password,
|
||||
});
|
||||
if (res && res.data) {
|
||||
const user = await axios.get(`${environment.strapiApiUrl}/users/${res.data.user.id}?populate=deep`);
|
||||
if (user && user.data) {
|
||||
res.data.user = {...res.data.user, ...user.data};
|
||||
}
|
||||
}
|
||||
return res.data;
|
||||
}
|
||||
|
||||
export async function lostPasswordStrapi({email}) {
|
||||
const res = await axios.post(`${environment.strapiApiUrl}/auth/forgot-password`, {email});
|
||||
if (res && res.data) {
|
||||
return res.data.ok;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function resetPasswordStrapi({password, passwordConfirmation, code}) {
|
||||
const res = await axios.post(`${environment.strapiApiUrl}/auth/reset-password`, {
|
||||
password,
|
||||
passwordConfirmation,
|
||||
code
|
||||
});
|
||||
if (res && res.data) {
|
||||
return !_.isNil(res.data.jwt);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
import delve from 'dlv';
|
||||
import {ImageLoader, ImageLoaderProps} from "next/image";
|
||||
import {isEmpty, isEqual} from "radash";
|
||||
|
||||
import {environment} from "../environments/environment";
|
||||
|
||||
export type ImageFormatType = "default" | "thumbnail" | "medium" | "small";
|
||||
|
||||
export interface PriceRange {
|
||||
min: number;
|
||||
max: number;
|
||||
}
|
||||
|
||||
export type SortType = 'pas' | 'pde' | 'alp';
|
||||
|
||||
export interface QueryParam {
|
||||
param: string;
|
||||
value: PriceRange | string | number[];
|
||||
}
|
||||
|
||||
export const buildQueriesListFromQueryParams = (query): QueryParam[] => {
|
||||
const queryMap = ['sort', 'cat', 'page', 'facets', 'filters', 'search'];
|
||||
|
||||
return queryMap.map((param: string) => {
|
||||
if (!isEmpty(query[param])) {
|
||||
let value = !isEmpty(query[param]) ? query[param] : null;
|
||||
|
||||
if (param === 'filters') {
|
||||
value = query[param].split(',').map((value: string) => parseInt(value, 10));
|
||||
}
|
||||
|
||||
if (param === 'facets') {
|
||||
const values = query[param].split(':');
|
||||
value = {min: parseInt(values[0], 10), max: parseInt(values[1], 10)};
|
||||
}
|
||||
|
||||
return ({param, value});
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}).filter((val) => !isEmpty(val));
|
||||
}
|
||||
|
||||
export const findQueryParamsValue = <T>(queryList: Array<{ param: string, value: T }>, params: string): T | null => {
|
||||
const paramGET = queryList.find((val: { param: string, value: T }) => val.param === params);
|
||||
return !isEmpty(paramGET) ? paramGET.value : null;
|
||||
}
|
||||
|
||||
export const getShopSortList = (): Array<{ value: SortType, label: string }> => {
|
||||
return [
|
||||
{value: "pas", label: 'Prix croissant'},
|
||||
{value: "pde", label: 'Prix décroissant'},
|
||||
{value: "alp", label: 'Ordre alphabetique'},
|
||||
];
|
||||
}
|
||||
|
||||
export const buildShopParamsGET = (sort: SortType = 'pas',
|
||||
page: number = null,
|
||||
range: PriceRange = {
|
||||
min: 0,
|
||||
max: 0
|
||||
},
|
||||
cat: string = null,
|
||||
filters: number[] = [],
|
||||
search: string) => {
|
||||
let url = `?sort=${sort}`;
|
||||
|
||||
if (!isEmpty(range) && !isEqual(range, {min: 0, max: 0})) {
|
||||
url += `&facets=${range.min}:${range.max}`;
|
||||
}
|
||||
if (!isEmpty(filters)) {
|
||||
url += `&filters=${filters.join(',')}`;
|
||||
}
|
||||
if (!isEmpty(cat)) {
|
||||
url += `&cat=${cat}`;
|
||||
}
|
||||
if (!isEmpty(page)) {
|
||||
url += `&page=${page}`;
|
||||
}
|
||||
if (!isEmpty(search)) {
|
||||
url += `&search=${search}`;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
export const contentfulImageLoader: ImageLoader = ({src, width}: ImageLoaderProps) => {
|
||||
return `${src}?w=${width}`
|
||||
}
|
||||
|
||||
export const getCategoryUrl = (item): string => {
|
||||
const categorySlug = !delve(item, 'attributes', null) ? delve(item, 'category.data.attributes.slug', '') : delve(item, 'attributes.category.data.attributes.slug', '');
|
||||
return '/blog/' + categorySlug;
|
||||
}
|
||||
|
||||
export const getPostUrl = (item): string => {
|
||||
const categorySlug = !delve(item, 'attributes', null) ? delve(item, 'category.data.attributes.slug', '') : delve(item, 'attributes.category.data.attributes.slug', '');
|
||||
const postSlug = !delve(item, 'attributes', null) ? delve(item, 'slug', '') : delve(item, 'attributes.slug', '');
|
||||
return '/blog/' + categorySlug + '/' + postSlug;
|
||||
}
|
||||
|
||||
export const getStrapiImage = (item, format: ImageFormatType = 'default') => {
|
||||
const image = !delve(item, 'attributes', null) ? delve(item, 'image.data.attributes', {}) : delve(item, 'attributes.image.data.attributes', {});
|
||||
switch (format) {
|
||||
case "default":
|
||||
return environment.strapiUrl + delve(image, "url", "/images/default.png");
|
||||
case "medium":
|
||||
return environment.strapiUrl + delve(image, "formats.medium.url", "/images/default.png");
|
||||
case "small":
|
||||
return environment.strapiUrl + delve(image, "formats.small.url", "/images/default.png");
|
||||
case "thumbnail":
|
||||
return environment.strapiUrl + delve(image, "formats.thumbnail.url", "/images/default.png");
|
||||
default:
|
||||
return environment.strapiUrl + delve(image, "url", "/images/default.png");
|
||||
}
|
||||
}
|
||||
|
||||
export const getStrapiImageSize = (item, format: ImageFormatType = 'default'): [number, number] => {
|
||||
const image = delve(item, 'attributes.image.data.attributes', {});
|
||||
switch (format) {
|
||||
case "default":
|
||||
return [delve(image, "width", 100), delve(image, "height", 100)];
|
||||
case "medium":
|
||||
return [delve(image, "formats.medium.width", 100), delve(image, "formats.medium.height", 100)];
|
||||
case "small":
|
||||
return [delve(image, "formats.small.width", 100), delve(image, "formats.small.height", 100)];
|
||||
case "thumbnail":
|
||||
return [delve(image, "formats.thumbnail.width", 100), delve(image, "formats.thumbnail.height", 100)];
|
||||
default:
|
||||
return [delve(image, "width", 100), delve(image, "height", 100)];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
@ -0,0 +1,36 @@
|
||||
//@ts-check
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { withNx } = require('@nrwl/next/plugins/with-nx');
|
||||
|
||||
/**
|
||||
* @type {import('@nrwl/next/plugins/with-nx').WithNxOptions}
|
||||
**/
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
poweredByHeader: false,
|
||||
output: 'standalone',
|
||||
compiler: {
|
||||
styledComponents: true
|
||||
},
|
||||
nx: {
|
||||
// Set this to true if you would like to to use SVGR
|
||||
// See: https://github.com/gregberge/svgr
|
||||
svgr: false
|
||||
},
|
||||
images: {
|
||||
loader: "default",
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'mcep.nasercloud.fr',
|
||||
}, {
|
||||
protocol: 'https',
|
||||
hostname: 'admin.mcep.nasercloud.fr',
|
||||
}
|
||||
],
|
||||
domains: ["localhost", "127.0.0.1", "admin.mcep.nasercloud.fr", "mcep.nasercloud.fr"],
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = withNx(nextConfig);
|
||||
@ -0,0 +1,21 @@
|
||||
import App, {AppProps} from 'next/app';
|
||||
import {ThemeProvider} from "next-themes";
|
||||
import {SessionProvider} from "next-auth/react";
|
||||
|
||||
import './styles.css';
|
||||
|
||||
function CustomApp({Component, pageProps}: AppProps) {
|
||||
pageProps = {...pageProps};
|
||||
return (
|
||||
<>
|
||||
<SessionProvider session={pageProps.session}>
|
||||
<ThemeProvider enableSystem={true}
|
||||
attribute="class">
|
||||
<Component {...pageProps} />
|
||||
</ThemeProvider>
|
||||
</SessionProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CustomApp;
|
||||
@ -0,0 +1,13 @@
|
||||
import {Head, Html, Main, NextScript} from 'next/document';
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang='en'>
|
||||
<Head/>
|
||||
<body>
|
||||
<Main/>
|
||||
<NextScript/>
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
};
|
||||
@ -0,0 +1,69 @@
|
||||
import NextAuth, {AuthOptions, Session, User} from 'next-auth';
|
||||
import CredentialsProvider from 'next-auth/providers/credentials';
|
||||
import {JWT} from "next-auth/jwt";
|
||||
import {AdapterUser} from "next-auth/adapters";
|
||||
|
||||
import {environment} from "../../../environments/environment";
|
||||
import {signInStrapi} from '../../../libs/auth';
|
||||
|
||||
export const authOptions: AuthOptions = {
|
||||
pages: {
|
||||
signIn: '/sign-in'
|
||||
},
|
||||
// Configure one or more authentication providers
|
||||
providers: [
|
||||
CredentialsProvider({
|
||||
name: 'Sign in with Email',
|
||||
credentials: {
|
||||
email: {label: 'Email', type: 'text'},
|
||||
password: {label: 'Password', type: 'password'},
|
||||
},
|
||||
async authorize(credentials, req) {
|
||||
/**
|
||||
* This function is used to define if the user is authenticated or not.
|
||||
* If authenticated, the function should return an object contains the user data.
|
||||
* If not, the function should return `null`.
|
||||
*/
|
||||
if (credentials == null) return null;
|
||||
/**
|
||||
* credentials is defined in the config above.
|
||||
* We can expect it contains two properties: `email` and `password`
|
||||
*/
|
||||
try {
|
||||
const {user, jwt} = await signInStrapi({
|
||||
email: credentials.email,
|
||||
password: credentials.password,
|
||||
});
|
||||
return {...user, jwt};
|
||||
} catch (error) {
|
||||
// Sign In Fail
|
||||
return null;
|
||||
}
|
||||
},
|
||||
}),
|
||||
],
|
||||
callbacks: {
|
||||
session: async ({session, token}: { session: Session, token: JWT }) => {
|
||||
(session as any).id = token.id;
|
||||
(session as any).jwt = token.jwt;
|
||||
(session as any).user = {
|
||||
avatar: (token.user as any).avatar,
|
||||
username: (token.user as any).username,
|
||||
email: (token.user as any).email,
|
||||
};
|
||||
return Promise.resolve(session);
|
||||
},
|
||||
jwt: async ({token, user}: { token: JWT, user: User | AdapterUser }) => {
|
||||
const isSignIn = user ? true : false;
|
||||
if (isSignIn) {
|
||||
token.id = user.id;
|
||||
token.jwt = (user as any).jwt;
|
||||
token.user = (user as any);
|
||||
}
|
||||
return Promise.resolve(token);
|
||||
},
|
||||
},
|
||||
secret: environment.nextAuthSecret
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions);
|
||||
@ -0,0 +1,2 @@
|
||||
.page {
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
import styles from './index.module.scss';
|
||||
import Layout from "../components/layout/layout";
|
||||
|
||||
export function Index() {
|
||||
/*
|
||||
* Replace the elements below with your own.
|
||||
*
|
||||
* Note: The corresponding styles are in the ./index.scss file.
|
||||
*/
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<Layout>
|
||||
<p>home page !</p>
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Index;
|
||||
@ -0,0 +1,18 @@
|
||||
import {withAuth} from "next-auth/middleware";
|
||||
|
||||
export default withAuth({
|
||||
callbacks: {
|
||||
authorized: async ({req}) => {
|
||||
const pathname = req.nextUrl.pathname;
|
||||
|
||||
if (pathname.startsWith('/_next') || pathname === '/favicon.ico' || pathname === '/__ENV.js') {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
},
|
||||
pages: {
|
||||
signIn: '/sign-in'
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Replace this with your own classes
|
||||
*
|
||||
* e.g.
|
||||
* .container {
|
||||
* }
|
||||
*/
|
||||
@ -0,0 +1,14 @@
|
||||
import styles from './index.module.scss';
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface LoginProps {}
|
||||
|
||||
export function SignIn(props: LoginProps) {
|
||||
return (
|
||||
<div className={styles['container']}>
|
||||
<h1>Welcome to Login!</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignIn;
|
||||
@ -0,0 +1,3 @@
|
||||
@tailwind components;
|
||||
@tailwind base;
|
||||
@tailwind utilities;
|
||||
@ -0,0 +1,15 @@
|
||||
const { join } = require('path');
|
||||
|
||||
// Note: If you use library-specific PostCSS/Tailwind configuration then you should remove the `postcssConfig` build
|
||||
// option from your application's configuration (i.e. project.json).
|
||||
//
|
||||
// See: https://nx.dev/guides/using-tailwind-css-in-react#step-4:-applying-configuration-to-libraries
|
||||
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {
|
||||
config: join(__dirname, 'tailwind.config.js'),
|
||||
},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "vendors",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/vendors",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nrwl/next:build",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"defaultConfiguration": "production",
|
||||
"options": {
|
||||
"root": "apps/vendors",
|
||||
"outputPath": "dist/apps/vendors"
|
||||
},
|
||||
"configurations": {
|
||||
"development": {
|
||||
"outputPath": "apps/vendors"
|
||||
},
|
||||
"production": {}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "@nrwl/next:server",
|
||||
"defaultConfiguration": "development",
|
||||
"options": {
|
||||
"buildTarget": "vendors:build",
|
||||
"dev": true,
|
||||
"port": 4300
|
||||
},
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "vendors:build:development",
|
||||
"dev": true
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "vendors:build:production",
|
||||
"dev": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"executor": "@nrwl/next:export",
|
||||
"options": {
|
||||
"buildTarget": "vendors:build:production"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "apps/vendors/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["apps/vendors/**/*.{ts,tsx,js,jsx}"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import Index from '../pages/index';
|
||||
|
||||
describe('Index', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<Index />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,17 @@
|
||||
const { createGlobPatternsForDependencies } = require('@nrwl/react/tailwind');
|
||||
const { join } = require('path');
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
join(
|
||||
__dirname,
|
||||
'{src,pages,components}/**/*!(*.stories|*.spec).{ts,tsx,html}'
|
||||
),
|
||||
...createGlobPatternsForDependencies(__dirname),
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
@ -0,0 +1,23 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "preserve",
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"incremental": true,
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "next-env.d.ts"],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"jest.config.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.ts"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"],
|
||||
"jsx": "react"
|
||||
},
|
||||
"include": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
Loading…
Reference in new issue