Compare commits
56 Commits
backend-te
...
8c4b9ceb9d
Author | SHA1 | Date | |
---|---|---|---|
8c4b9ceb9d | |||
647812576e | |||
2dfee66958 | |||
2b1666c949 | |||
0c724cae7f | |||
6de45801d2 | |||
03897e1139 | |||
00a733c03b | |||
3dc8131c33 | |||
7c271d8c47 | |||
259d56271c | |||
b9f3bbbe15 | |||
14a2a59786 | |||
0ae6e7dfda | |||
15ccb5630a | |||
4ec292cca7 | |||
14a953536a | |||
288f983816 | |||
dd6032f3ef | |||
7e2f5bc506 | |||
4ef92efd0e | |||
e769dd6757 | |||
550a51523f | |||
323cb05388 | |||
7e0851bfef | |||
98b6d167e8 | |||
79baddb8f6 | |||
0f8c83c2e2 | |||
fad52644d2 | |||
5f51a1008b | |||
279c171ba2 | |||
9ba8e3e84e | |||
6de38a9725 | |||
067eeb9494 | |||
f48b570494 | |||
0733f8d5af | |||
8071c01c5d | |||
b355463dd9 | |||
4ee3d9bc44 | |||
d75d45e204 | |||
79e949bdd4 | |||
9f3754776f | |||
651fb2b1a1 | |||
aa5988ce75 | |||
9ae18e1e4b | |||
ef8c8e896d | |||
22ebb0e1f4 | |||
09e4b3262f | |||
6a3d4239ab | |||
9d71c93b5b | |||
5145b833ae | |||
4080cee818 | |||
f4d73654d1 | |||
4fda5513a9 | |||
32407b0e8f | |||
b30e1196f4 |
741
Documentation/openapi/main.yaml
Normal file
741
Documentation/openapi/main.yaml
Normal file
@ -0,0 +1,741 @@
|
|||||||
|
openapi: 3.0.3
|
||||||
|
info:
|
||||||
|
title: MyInpulse Backend Api
|
||||||
|
description: this document servers as a documentation for the backend api.
|
||||||
|
version: 0.0.0
|
||||||
|
|
||||||
|
tags:
|
||||||
|
- name: Entrepreneurs API
|
||||||
|
description: La partie de l'api dédiée aux entrepreneurs
|
||||||
|
- name: Admin API
|
||||||
|
description: La partie de l'api dédiée aux entrepreneurs
|
||||||
|
- name: Shared API
|
||||||
|
description: La partie de l'api dédiée aux entrepreneurs et admins
|
||||||
|
|
||||||
|
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
user:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
nom:
|
||||||
|
type: string
|
||||||
|
prenom:
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
example: "example@exmaple.com"
|
||||||
|
secondaryEmail:
|
||||||
|
type: string
|
||||||
|
example: "example@exmaple.com"
|
||||||
|
tel:
|
||||||
|
type: string
|
||||||
|
example: "0612345678"
|
||||||
|
user-entrepreneur:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
user:
|
||||||
|
$ref: "#/components/schemas/user"
|
||||||
|
entrepreneur:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ecole:
|
||||||
|
type: string
|
||||||
|
example: "enseirb"
|
||||||
|
filiere:
|
||||||
|
type: string
|
||||||
|
example: "info"
|
||||||
|
status:
|
||||||
|
type: boolean
|
||||||
|
example: false
|
||||||
|
user-admin:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
admin:
|
||||||
|
$ref: "#/components/schemas/user"
|
||||||
|
|
||||||
|
securitySchemes:
|
||||||
|
MyINPulse:
|
||||||
|
type: oauth2
|
||||||
|
flows:
|
||||||
|
implicit:
|
||||||
|
authorizationUrl: https://petstore3.swagger.io/oauth/authorize
|
||||||
|
scopes:
|
||||||
|
MyINPulse-admin: Administrateur
|
||||||
|
MyINPulse-entrepreneur: Utilisateur
|
||||||
|
|
||||||
|
paths:
|
||||||
|
|
||||||
|
# _ ____ __ __ ___ _ _ _ ____ ___
|
||||||
|
# / \ | _ \| \/ |_ _| \ | | / \ | _ \_ _|
|
||||||
|
# / _ \ | | | | |\/| || || \| | / _ \ | |_) | |
|
||||||
|
# / ___ \| |_| | | | || || |\ | / ___ \| __/| |
|
||||||
|
# /_/ \_\____/|_| |_|___|_| \_| /_/ \_\_| |___|
|
||||||
|
#
|
||||||
|
|
||||||
|
/admin/projects:
|
||||||
|
get:
|
||||||
|
summary: Retourne la liste of projets associés à l'admin
|
||||||
|
tags:
|
||||||
|
- Admin API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
description:
|
||||||
|
JSON array of who's elements are objects containing necessary information for the view
|
||||||
|
(project name, entrepreneur names, etc..)
|
||||||
|
of the projects an admin is watching over.
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
E_names:
|
||||||
|
type: string
|
||||||
|
description: entrepreneur names
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is missing or invalid
|
||||||
|
/admin/projects/pending/decision:
|
||||||
|
post:
|
||||||
|
summary: valider un projet en attente de validation
|
||||||
|
tags:
|
||||||
|
- Admin API
|
||||||
|
description:
|
||||||
|
if the request is accepted the status of the
|
||||||
|
project is changed to ongoing, entrepreneur
|
||||||
|
account is confirmed and the project is linked
|
||||||
|
to the admin accepting the request and the
|
||||||
|
entrepreneur requesting it. Else the pending
|
||||||
|
project and user info are deleted.
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
pedingProjectId:
|
||||||
|
type: integer
|
||||||
|
decision:
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
|
||||||
|
/admin/projects/add:
|
||||||
|
post:
|
||||||
|
summary: Ajout manuel d'un projet
|
||||||
|
description:
|
||||||
|
Adds a project with the
|
||||||
|
inputed details
|
||||||
|
tags:
|
||||||
|
- Admin API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
founder:
|
||||||
|
$ref: "#/components/schemas/user-entrepreneur"
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
|
||||||
|
/admin/appointments/report/{appointmentId}:
|
||||||
|
put:
|
||||||
|
summary: enregistrer un rapport du rendez-vous
|
||||||
|
description:
|
||||||
|
Generate a PDF file formatted
|
||||||
|
from input text and links it
|
||||||
|
to the appointement.
|
||||||
|
tags:
|
||||||
|
- Admin API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: appointmentId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
body:
|
||||||
|
type: string
|
||||||
|
conclusion:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
post:
|
||||||
|
summary: modifier un rapport déja éxistant du rendez-vous
|
||||||
|
description:
|
||||||
|
Modifies the report file to input
|
||||||
|
text and links it to the appointement.
|
||||||
|
tags:
|
||||||
|
- Admin API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: appointmentId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
body:
|
||||||
|
type: string
|
||||||
|
conclusion:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
|
||||||
|
|
||||||
|
/admin/projects/remove/{projectId}:
|
||||||
|
delete:
|
||||||
|
summary: supression d'un project
|
||||||
|
description:
|
||||||
|
Removes the project
|
||||||
|
with the inputed id projectId
|
||||||
|
tags:
|
||||||
|
- Admin API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: projectId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
|
||||||
|
|
||||||
|
/admin/projects/pending:
|
||||||
|
get:
|
||||||
|
summary: Retourne la liste des projets en attente de validation
|
||||||
|
tags:
|
||||||
|
- Admin API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
description:
|
||||||
|
JSON array of who's elements are objects containing
|
||||||
|
necessary information for the view (project name,
|
||||||
|
entrepreneur names, etc..) of all pending projects.
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
founder:
|
||||||
|
$ref: "#/components/schemas/user-entrepreneur"
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is missing or invalid
|
||||||
|
|
||||||
|
#
|
||||||
|
# ____ _ _ _ ____ ___
|
||||||
|
# / ___|| |__ __ _ _ __ ___ __| | / \ | _ \_ _|
|
||||||
|
# \___ \| '_ \ / _` | '__/ _ \/ _` | / _ \ | |_) | |
|
||||||
|
# ___) | | | | (_| | | | __/ (_| | / ___ \| __/| |
|
||||||
|
# |____/|_| |_|\__,_|_| \___|\__,_| /_/ \_\_| |___|
|
||||||
|
#
|
||||||
|
|
||||||
|
/shared/appointments/upcoming:
|
||||||
|
get:
|
||||||
|
summary: Retourne la list des prochains rendez-vous de l'utilisateur
|
||||||
|
tags:
|
||||||
|
- Shared API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
- MyINPulse-entrepreneur
|
||||||
|
description:
|
||||||
|
JSON array of upcoming appointment data (name, date, time etc..) for a user.
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
date:
|
||||||
|
type: string
|
||||||
|
time:
|
||||||
|
type: string
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is missing or invalid
|
||||||
|
|
||||||
|
/shared/projects/lcsection/{projectId}/{title}/{date}:
|
||||||
|
get:
|
||||||
|
summary: Retourne la liste de sections de LC avec un titre donné
|
||||||
|
tags:
|
||||||
|
- Shared API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
- MyINPulse-entrepreneur
|
||||||
|
description:
|
||||||
|
JSON array containing Lean Canvas
|
||||||
|
section data with a title for the
|
||||||
|
current date (or given date if the
|
||||||
|
date parameter is passed)
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
required: true
|
||||||
|
name: projectId
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
- in: path
|
||||||
|
required: true
|
||||||
|
description: this number can be 1, 2,...,8. It is associated with the title of the lcsection
|
||||||
|
name: title
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
enum: [1, 2, 3, 4, 5, 6, 7, 8]
|
||||||
|
|
||||||
|
- in: path
|
||||||
|
required: true
|
||||||
|
name: date
|
||||||
|
description: the date corresponding to the wanted version of lc section. "Nan" for the latest version
|
||||||
|
example: "NaN"
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
section:
|
||||||
|
type: string
|
||||||
|
txt:
|
||||||
|
type: string
|
||||||
|
time:
|
||||||
|
type: string
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is missing or invalid
|
||||||
|
|
||||||
|
/shared/projects/entrepreneurs/{projectId}:
|
||||||
|
get:
|
||||||
|
summary: Retourne la liste d'entrepreneurs associée à un projet donné
|
||||||
|
tags:
|
||||||
|
- Shared API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
- MyINPulse-entrepreneur
|
||||||
|
description:
|
||||||
|
JSON array of entrepreneur
|
||||||
|
names associated with a project
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: projectId
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/user-entrepreneur"
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is missing or invalid
|
||||||
|
|
||||||
|
/shared/projects/admin/{projectId}:
|
||||||
|
get:
|
||||||
|
summary: Retourne les informations de l'admin qui accompagne le projet
|
||||||
|
tags:
|
||||||
|
- Shared API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
- MyINPulse-entrepreneur
|
||||||
|
description:
|
||||||
|
JSON object containing information (name, gmail, tel, etc..)
|
||||||
|
the admin supervising the project with id projectID.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: projectId
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/user-admin"
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
|
||||||
|
/shared/projects/appointments/{projectId}:
|
||||||
|
get:
|
||||||
|
summary: Retourne les rendez-vous du projet
|
||||||
|
tags:
|
||||||
|
- Shared API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
- MyINPulse-entrepreneur
|
||||||
|
description:
|
||||||
|
JSON array of upcoming and past appointment
|
||||||
|
data for the project with id projectID.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: projectId
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
appointementId:
|
||||||
|
type: integer
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
date:
|
||||||
|
type: string
|
||||||
|
time:
|
||||||
|
type: string
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
/shared/projects/appointments/report/{apointementId}:
|
||||||
|
get:
|
||||||
|
summary: Retourne le rapport pdf du rendez-vous
|
||||||
|
tags:
|
||||||
|
- Shared API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-admin
|
||||||
|
- MyINPulse-entrepreneur
|
||||||
|
description:
|
||||||
|
PDF file containing the ap-
|
||||||
|
pointment report
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: apointementId
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/pdf:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: binary
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
|
||||||
|
/shared/appointments/request:
|
||||||
|
post:
|
||||||
|
summary: demander un rendez-vous
|
||||||
|
description:
|
||||||
|
will add an appointement request request by the applicant
|
||||||
|
to have an appointment to be confirmed or denied by the
|
||||||
|
specified participants of the appointement.
|
||||||
|
tags:
|
||||||
|
- Shared API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-entrepreneur
|
||||||
|
- MyINPulse-admin
|
||||||
|
requestBody:
|
||||||
|
description: \"participants\" property is an array containing userids of the participants in the appointement
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
start_time:
|
||||||
|
type: string
|
||||||
|
end_time:
|
||||||
|
type: string
|
||||||
|
place:
|
||||||
|
type: string
|
||||||
|
applicantId:
|
||||||
|
type: integer
|
||||||
|
participants:
|
||||||
|
#/* */
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: integer
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# _____ _ _ _____ ____ _____ ____ ____ _____ _ _ _____ _ _ ____
|
||||||
|
# | ____| \ | |_ _| _ \| ____| _ \| _ \| ____| \ | | ____| | | | _ \
|
||||||
|
# | _| | \| | | | | |_) | _| | |_) | |_) | _| | \| | _| | | | | |_) |
|
||||||
|
# | |___| |\ | | | | _ <| |___| __/| _ <| |___| |\ | |___| |_| | _ <
|
||||||
|
# |_____|_|_\_| |_| |_| \_\_____|_| |_| \_\_____|_| \_|_____|\___/|_| \_\
|
||||||
|
# / \ | _ \_ _|
|
||||||
|
# / _ \ | |_) | |
|
||||||
|
# / ___ \| __/| |
|
||||||
|
# /_/ \_\_| |___|
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
/entrepreneur/projects/request:
|
||||||
|
post:
|
||||||
|
summary: demander la création et validation d'un projet
|
||||||
|
tags:
|
||||||
|
- Entrepreneurs API
|
||||||
|
description:
|
||||||
|
Adds project to pending projects
|
||||||
|
to then be accepted or rejected by
|
||||||
|
an admin
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-entrepreneur
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
founder:
|
||||||
|
$ref: "#/components/schemas/user-entrepreneur"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
|
||||||
|
|
||||||
|
/entrepreneur/lcsection/add/{projectId}:
|
||||||
|
post:
|
||||||
|
summary: ajouter une sections au LC
|
||||||
|
description:
|
||||||
|
Adds input data to the user's LC
|
||||||
|
with a specified title.
|
||||||
|
tags:
|
||||||
|
- Entrepreneurs API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-entrepreneur
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: projectId
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
required: true
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
txt:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
/entrepreneur/lcsection/modify/{sectionId}:
|
||||||
|
put:
|
||||||
|
summary: modifier les données d'une section LC
|
||||||
|
description:
|
||||||
|
Modifies input Lean Canvas section by changing it to
|
||||||
|
the information in the request body and changes the
|
||||||
|
time stamp.
|
||||||
|
tags:
|
||||||
|
- Entrepreneurs API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-entrepreneur
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: sectionId
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
required: true
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
txt:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
|
||||||
|
/entrepreneur/lcsection/remove/{sectionId}:
|
||||||
|
delete:
|
||||||
|
summary: supprimer une section LC.
|
||||||
|
description:
|
||||||
|
Deletes section from Lean Canvas
|
||||||
|
tags:
|
||||||
|
- Entrepreneurs API
|
||||||
|
security:
|
||||||
|
- MyINPulse:
|
||||||
|
- MyINPulse-entrepreneur
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: sectionId
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
"401":
|
||||||
|
description: Authorization information is
|
||||||
|
missing or invalid
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
3
Makefile
3
Makefile
@ -33,6 +33,8 @@ dev-front: clean vite keycloak
|
|||||||
@cp config/frontdev.docker-compose.yaml docker-compose.yaml
|
@cp config/frontdev.docker-compose.yaml docker-compose.yaml
|
||||||
@docker compose up -d --build
|
@docker compose up -d --build
|
||||||
@cd ./front/MyINPulse-front/ && npm run dev
|
@cd ./front/MyINPulse-front/ && npm run dev
|
||||||
|
@echo "cd MyINPulse-back" && echo 'export $$(cat .env | xargs)'
|
||||||
|
@echo "./gradlew bootRun --args='--server.port=8081'"
|
||||||
|
|
||||||
prod: clean keycloak
|
prod: clean keycloak
|
||||||
@cp config/prod.env front/MyINPulse-front/.env
|
@cp config/prod.env front/MyINPulse-front/.env
|
||||||
@ -43,6 +45,7 @@ prod: clean keycloak
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dev-back: keycloak
|
dev-back: keycloak
|
||||||
@cp config/backdev.env front/MyINPulse-front/.env
|
@cp config/backdev.env front/MyINPulse-front/.env
|
||||||
@cp config/backdev.env .env
|
@cp config/backdev.env .env
|
||||||
|
0
front/Dockerfile
Normal file → Executable file
0
front/Dockerfile
Normal file → Executable file
63
front/MyINPulse-front/fake_data/db.json
Normal file
63
front/MyINPulse-front/fake_data/db.json
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"entrepreneurs": [
|
||||||
|
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
|
||||||
|
{ "id": 2, "name": "Bob", "email": "bob@example.com" },
|
||||||
|
{ "id": 3, "name": "Charlie", "email": "charlie@example.com" }
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 1,
|
||||||
|
"title_text": "1. Problème",
|
||||||
|
"description": "3 problèmes essentiels à résoudre pour le client"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 2,
|
||||||
|
"title_text": "2. Segments",
|
||||||
|
"description": "Les segments de clientèle visés"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 3,
|
||||||
|
"title_text": "3. Valeur",
|
||||||
|
"description": "La proposition de valeur"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 4,
|
||||||
|
"title_text": "4. Solution",
|
||||||
|
"description": "Les solutions proposées"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 5,
|
||||||
|
"title_text": "5. Avantage",
|
||||||
|
"description": "Les avantages concurrentiels"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 6,
|
||||||
|
"title_text": "6. Canaux",
|
||||||
|
"description": "Les canaux de distribution"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 7,
|
||||||
|
"title_text": "7. Indicateurs",
|
||||||
|
"description": "Les indicateurs clés de performance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 8,
|
||||||
|
"title_text": "8. Coûts",
|
||||||
|
"description": "Les coûts associés"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 9,
|
||||||
|
"title_text": "9. Revenus",
|
||||||
|
"description": "Les sources de revenus"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
2
front/MyINPulse-front/fake_data/open.sh
Executable file
2
front/MyINPulse-front/fake_data/open.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
json-server --watch db.json --port 5000
|
@ -1,47 +1,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouterView } from "vue-router";
|
import { RouterLink, RouterView } from 'vue-router'
|
||||||
import ErrorWrapper from "@/views/errorWrapper.vue";
|
import ErrorWrapper from "@/views/errorWrapper.vue";
|
||||||
import ProjectComponent from "@/components/ProjectComponent.vue";
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<HeaderComponent />
|
|
||||||
<error-wrapper></error-wrapper>
|
<Header />
|
||||||
<div id="main">
|
<ErrorWrapper />
|
||||||
<ProjectComponent
|
<!--<RouterLink to="/">Home</RouterLink> | -->
|
||||||
v-for="(project, index) in projects"
|
<!--<RouterLink to="/canvas">Canvas</RouterLink> -->
|
||||||
:key="index"
|
|
||||||
:project-name="project.name"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<RouterView />
|
<RouterView />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import HeaderComponent from "@/components/HeaderComponent.vue";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "App",
|
|
||||||
components: {
|
|
||||||
HeaderComponent,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
projects: [
|
|
||||||
{
|
|
||||||
name: "Projet Alpha",
|
|
||||||
//link: './project-alpha.html',
|
|
||||||
//members: ['Alice', 'Bob', 'Charlie'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Projet Beta",
|
|
||||||
//link: './project-beta.html',
|
|
||||||
//members: ['David', 'Eve', 'Frank'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
|
75
front/MyINPulse-front/src/components/Agenda.vue
Normal file
75
front/MyINPulse-front/src/components/Agenda.vue
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div id="agenda">
|
||||||
|
<h3>Rendez-vous</h3>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for=" (p, index) in projectRDV" :key="index" >
|
||||||
|
<td>{{ p.projectName }} </td> <td>{{ p.date }}</td> <td>{{ p.lieu }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineProps } from "vue";
|
||||||
|
|
||||||
|
interface rendezVous{
|
||||||
|
projectName: String,
|
||||||
|
date: String,
|
||||||
|
lieu: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
projectRDV: rendezVous[]
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#agenda {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table Styling */
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
text-align: left;
|
||||||
|
margin-top: 20px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header Row (if exists) */
|
||||||
|
th {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
padding: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table Body Rows */
|
||||||
|
tbody tr {
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
transition: background-color 0.2s ease; /* Smooth hover effect */
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr:hover {
|
||||||
|
background-color: #f9f9f9; /* Highlight row on hover */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cells Styling */
|
||||||
|
td {
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
font-size: 14px;
|
||||||
|
vertical-align: middle; /* Align text to middle */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First Column Styling */
|
||||||
|
td:first-child {
|
||||||
|
text-align: center;
|
||||||
|
width: 50px; /* Adjust width as needed */
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -1,21 +1,130 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="project">
|
<div @click="goToLink" class="project">
|
||||||
<div class="project-header">
|
<div class="project-header">
|
||||||
<h2>{{ projectName }}</h2>
|
<h2 >{{ projectName }}</h2>
|
||||||
|
<div class="project-buttons">
|
||||||
|
<button class="contact-btn">Contact</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="project-body">
|
||||||
|
<ul>
|
||||||
|
<li v-for="(name, index) in listName" :key="index">{{ name }}</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import type { PropType } from "vue";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "ProjectComponent",
|
<script setup lang="ts">
|
||||||
props: {
|
import { defineProps } from "vue";
|
||||||
projectName: {
|
import { useRouter } from 'vue-router'
|
||||||
type: Object as PropType<string>,
|
|
||||||
required: true,
|
|
||||||
},
|
const props = defineProps<{
|
||||||
},
|
projectName: string;
|
||||||
|
listName: string[];
|
||||||
|
projectLink: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const goToLink = () => {
|
||||||
|
if (props.projectLink) {
|
||||||
|
router.push(props.projectLink);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.project {
|
||||||
|
background: linear-gradient(to right, #f4f4f4, #ffffff);
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header Styling */
|
||||||
|
.project-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-header h2 {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button Container */
|
||||||
|
.project-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.info-btn {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-btn:hover {
|
||||||
|
background-color: #45a049;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-btn {
|
||||||
|
background-color: #007BFF;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-btn:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.project-body {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-body p {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #555;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-body ul {
|
||||||
|
list-style-type: disc;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-body ul li {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 10px 15px;
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
359
front/MyINPulse-front/src/components/canvas/CanvasItem.vue
Executable file
359
front/MyINPulse-front/src/components/canvas/CanvasItem.vue
Executable file
@ -0,0 +1,359 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="['cell', { expanded }]" @click="handleClick">
|
||||||
|
<h3>{{ title_text }}</h3>
|
||||||
|
|
||||||
|
<div class="section-bloc" v-for="(desc, index) in currentDescriptions" :key="index">
|
||||||
|
|
||||||
|
<!-- ADMIN -------------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<template v-if="IS_ADMIN">
|
||||||
|
<div class="description">
|
||||||
|
<p>{{ desc }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- ENTREP ------------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<template v-if="!IS_ADMIN">
|
||||||
|
<!-- Mode affichage -->
|
||||||
|
<template v-if="!isEditing[index]">
|
||||||
|
<div class="description">
|
||||||
|
<p>{{ desc }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="button-container">
|
||||||
|
<button v-if="expanded" @click.stop="startEditing(index)" class="edit-button">Éditer</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Mode édition -->
|
||||||
|
<template v-else>
|
||||||
|
<textarea v-model="editedDescriptions[index]" class="edit-input"></textarea>
|
||||||
|
<div class="button-container">
|
||||||
|
<button @click.stop="saveEdit(index)" class="save-button">Enregistrer</button>
|
||||||
|
<button @click.stop="cancelEdit(index)" class="cancel-button">Annuler</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<!---------------------------------------------------------------------------------------------------->
|
||||||
|
<template v-if="expanded">
|
||||||
|
<div class="canvas-exit-hint">
|
||||||
|
Cliquez n'importe où pour quitter le canvas
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, defineProps } from "vue";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const IS_MOCK_MODE = true;
|
||||||
|
const IS_ADMIN = false;
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
projectId: number;
|
||||||
|
title: number;
|
||||||
|
title_text: string;
|
||||||
|
description: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const expanded = ref(false);
|
||||||
|
const currentDescriptions = ref<string[]>([]);
|
||||||
|
currentDescriptions.value[0] = props.description;
|
||||||
|
const editedDescriptions = ref<string[]>([]);
|
||||||
|
const isEditing = ref<boolean[]>([]);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get("http://localhost:5000/data"); // Met à jour l'URL
|
||||||
|
if (response.data.length > 0) {
|
||||||
|
currentDescription.value = response.data[0].canva_data;
|
||||||
|
editedDescription.value = response.data[0].canva_data;
|
||||||
|
} else {
|
||||||
|
console.warn("Aucune donnée reçue.");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la récupération des données :", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Fonction fetchData avec possibilité d'utiliser le mock
|
||||||
|
const fetchData = async (projectId: number, title: number, date: string, useMock = false) => {
|
||||||
|
try {
|
||||||
|
const responseData = useMock
|
||||||
|
? await mockFetch(projectId, title, date)
|
||||||
|
: (await axios.get<{ txt: string }[]>(
|
||||||
|
`http://localhost:5000/shared/projects/lcsection/${projectId}/${title}/${date}`
|
||||||
|
)).data;
|
||||||
|
|
||||||
|
if (responseData.length > 0) {
|
||||||
|
currentDescriptions.value = responseData.map((item) => item.txt);
|
||||||
|
editedDescriptions.value = [...currentDescriptions.value];
|
||||||
|
isEditing.value = Array(responseData.length).fill(false);
|
||||||
|
} else {
|
||||||
|
console.warn("Aucune donnée reçue.");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la récupération des données :", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Fonction de simulation de l'API
|
||||||
|
const mockFetch = async (projectId: number, title: number, date: string) => {
|
||||||
|
console.log(`Mock fetch pour projectId: ${projectId}, title: ${title}, date: ${date}`);
|
||||||
|
|
||||||
|
return new Promise<{ txt: string }[]>((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve([
|
||||||
|
{txt: "Ceci est une description 1 pour tester le front. Franchement, si tu es encore en train de lire, c’est probablement que tu veux t'assurer que tout s’affiche bien même avec un texte bien long. Allez, encore quelques mots inutiles pour bien remplir la ligne et tester les retours à la ligne. Bravo champion."},
|
||||||
|
{txt: "Deuxième description : elle est là pour t’aider à tester le comportement du composant avec du texte plus dense. Peut-être même avec quelques caractères spéciaux, tiens : éèàçù$#@! Et si on faisait semblant d’avoir du contenu sérieux ? Non, toujours pas."},
|
||||||
|
{txt: "Troisième description, probablement inutile mais bon, on continue pour la forme. À ce stade, tu testes sûrement si le champ de texte peut supporter un pavé sans exploser. Spoiler alert : si t'as tout bien codé, ça devrait aller. Sinon, bah... débogue. Courage."}
|
||||||
|
]);
|
||||||
|
}, 500); // Simule un délai réseau de 500ms
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Utilisation du mock dans handleClick pour tester sans serveur
|
||||||
|
const handleClick = async () => {
|
||||||
|
if (!expanded.value) {
|
||||||
|
await fetchData(props.projectId, props.title, "NaN", IS_MOCK_MODE);
|
||||||
|
} else if (!isEditing.value.includes(true)) {
|
||||||
|
// Réinitialiser les descriptions si aucune édition n'est en cours
|
||||||
|
currentDescriptions.value = [props.description];
|
||||||
|
editedDescriptions.value = [props.description];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEditing.value.includes(true)) {
|
||||||
|
expanded.value = !expanded.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const startEditing = (index: number) => {
|
||||||
|
isEditing.value[index] = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
const saveEdit = async (index: number) => {
|
||||||
|
try {
|
||||||
|
const id = index + 1; // À adapter selon l'ID réel des données
|
||||||
|
await axios.put(`http://localhost:5000/data/${id}`, {
|
||||||
|
canva_data: editedDescriptions.value[index]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mettre à jour l'affichage local après la mise à jour réussie
|
||||||
|
currentDescriptions.value[index] = editedDescriptions.value[index];
|
||||||
|
isEditing.value[index] = false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la mise à jour des données :", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
const saveEdit = async (index: number) => {
|
||||||
|
if (IS_MOCK_MODE) {
|
||||||
|
await mockSaveEdit(index);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const id = index + 1;
|
||||||
|
await axios.put(`http://localhost:5000/data/${id}`, {
|
||||||
|
canva_data: editedDescriptions.value[index]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mettre à jour l'affichage local après la mise à jour réussie
|
||||||
|
currentDescriptions.value[index] = editedDescriptions.value[index];
|
||||||
|
isEditing.value[index] = false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la mise à jour des données :", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fonction de mock pour l'enregistrement
|
||||||
|
const mockSaveEdit = async (index: number) => {
|
||||||
|
try {
|
||||||
|
const id = index + 1;
|
||||||
|
console.log(`Mock save pour l'ID ${id} avec la description : ${editedDescriptions.value[index]}`);
|
||||||
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 500)); // Simulation de délai réseau
|
||||||
|
|
||||||
|
// Mettre à jour l'affichage local après la mise à jour réussie
|
||||||
|
currentDescriptions.value[index] = editedDescriptions.value[index];
|
||||||
|
isEditing.value[index] = false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la mise à jour des données mockées :", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelEdit = (index: number) => {
|
||||||
|
editedDescriptions.value[index] = currentDescriptions.value[index];
|
||||||
|
isEditing.value[index] = false;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@import "@/components/canvas/style-project.css";
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.expanded-content {
|
||||||
|
justify-content: flex-start !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell:not(.expanded):hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 8px 9px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell h3 {
|
||||||
|
font-size: 25px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p {
|
||||||
|
font-size: 25px;
|
||||||
|
color: #666;
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expanded {
|
||||||
|
padding-top: 10%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: white;
|
||||||
|
z-index: 10;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.description {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-left: 2%;
|
||||||
|
margin-right: 4%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description + .p {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-top: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-left: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.button-container {
|
||||||
|
display: block;
|
||||||
|
margin-top: 20px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding-right: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-bloc ,.editing-section-bloc {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
margin-right: 10%;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-button {
|
||||||
|
width: 100px;
|
||||||
|
height: 40px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-button, .cancel-button {
|
||||||
|
width: 100px;
|
||||||
|
height: 40px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-button {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-button {
|
||||||
|
background-color: #28a745;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button {
|
||||||
|
background-color: #dc3545;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-button:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-button:hover {
|
||||||
|
background-color: #218838;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button:hover {
|
||||||
|
background-color: #c82333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas-exit-hint {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #666;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
182
front/MyINPulse-front/src/components/canvas/HeaderCanvas.vue
Normal file
182
front/MyINPulse-front/src/components/canvas/HeaderCanvas.vue
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
<template>
|
||||||
|
<header class="header">
|
||||||
|
<img src="../icons/logo inpulse.png" alt="INPulse Logo" class="logo" />
|
||||||
|
|
||||||
|
<div class="header-actions">
|
||||||
|
<div class="dropdown-wrapper">
|
||||||
|
<button class="contact-button" @click="toggleDropdown">Contact</button>
|
||||||
|
<div class="contact-dropdown" :class="{ 'dropdown-visible': isDropdownOpen }">
|
||||||
|
<button @click="contactAll">Contacter tous</button>
|
||||||
|
<button v-for="(email, index) in entrepreneurEmails" :key="index">
|
||||||
|
{{ email }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<RouterLink to="/" class="return-button">Retour</RouterLink>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const IS_MOCK_MODE = true;
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
projectId: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
type Entrepreneur = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
primaryMail: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isDropdownOpen = ref(false);
|
||||||
|
const entrepreneurEmails = ref([]);
|
||||||
|
|
||||||
|
const toggleDropdown = () => {
|
||||||
|
isDropdownOpen.value = !isDropdownOpen.value;
|
||||||
|
console.log("Dropdown toggled:", isDropdownOpen.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const fetchEntrepreneurs = async (projectId :number, useMock = IS_MOCK_MODE) => {
|
||||||
|
try {
|
||||||
|
const responseData = useMock
|
||||||
|
? await mockFetchEntrepreneurs(projectId)
|
||||||
|
: (await axios.get(`http://localhost:5000/shared/projects/entrepreneurs/${projectId}`)).data;
|
||||||
|
|
||||||
|
if (responseData.length > 0) {
|
||||||
|
entrepreneurEmails.value = responseData.map((item) => item.primaryMail);
|
||||||
|
} else {
|
||||||
|
console.warn("Aucun entrepreneur trouvé.");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la récupération des entrepreneurs :", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fonction de simulation de l'API
|
||||||
|
const mockFetchEntrepreneurs = async (projectId :number) => {
|
||||||
|
console.log(`Mock fetch pour projectId: ${projectId}`);
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve([
|
||||||
|
{
|
||||||
|
idUser: 1,
|
||||||
|
userSurname: "Doe",
|
||||||
|
userName: "John",
|
||||||
|
primaryMail: "john.doe@example.com",
|
||||||
|
secondaryMail: "johndoe@backup.com",
|
||||||
|
phoneNumber: "612345678",
|
||||||
|
school: "ENSEIRB",
|
||||||
|
course: "Info",
|
||||||
|
sneeStatus: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
idUser: 2,
|
||||||
|
userSurname: "Smith",
|
||||||
|
userName: "Jane",
|
||||||
|
primaryMail: "jane.smith@example.com",
|
||||||
|
secondaryMail: "janesmith@backup.com",
|
||||||
|
phoneNumber: "698765432",
|
||||||
|
school: "ENSEIRB",
|
||||||
|
course: "Info",
|
||||||
|
sneeStatus: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const contactAll = () => {
|
||||||
|
alert("Contacter tous les entrepreneurs : " + entrepreneurEmails.value.join(", "));
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => fetchEntrepreneurs(props.projectId, IS_MOCK_MODE));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@import "@/components/canvas/style-project.css";
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 15px 30px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-button,
|
||||||
|
.return-button {
|
||||||
|
background-color: #009CDE;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.return-button:hover,
|
||||||
|
.contact-button:hover {
|
||||||
|
background-color: #007bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.contact-dropdown {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
background-color: #000;
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0px 4px 8px rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
z-index: 1000;
|
||||||
|
min-width: 200px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-dropdown button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 5px;
|
||||||
|
text-align: left;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-dropdown button:hover {
|
||||||
|
background-color: #009CDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-dropdown.dropdown-visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
59
front/MyINPulse-front/src/components/canvas/LeanCanvas.vue
Normal file
59
front/MyINPulse-front/src/components/canvas/LeanCanvas.vue
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<template>
|
||||||
|
<div class="canvas">
|
||||||
|
<CanvasItem
|
||||||
|
v-for="(item, index) in items"
|
||||||
|
:key="index"
|
||||||
|
:title="item.title"
|
||||||
|
:title_text="item.title_text"
|
||||||
|
:description="item.description"
|
||||||
|
:projectId="item.projectId"
|
||||||
|
:class="item.class"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
import CanvasItem from "@/components/canvas/CanvasItem.vue";
|
||||||
|
|
||||||
|
const items = ref([
|
||||||
|
{ projectId: 1, title: 1, title_text: "1. Problème", description: "3 problèmes essentiels à résoudre pour le client", class: "Probleme" },
|
||||||
|
{ projectId: 1, title: 2, title_text: "2. Segments", description: "Les segments de clientèle visés", class: "Segments" },
|
||||||
|
{ projectId: 1, title: 3, title_text: "3. Valeur", description: "La proposition de valeur", class: "Valeur" },
|
||||||
|
{ projectId: 1, title: 4, title_text: "4. Solution", description: "Les solutions proposées", class: "Solution" },
|
||||||
|
{ projectId: 1, title: 5, title_text: "5. Avantage", description: "Les avantages concurrentiels", class: "Avantage" },
|
||||||
|
{ projectId: 1, title: 6, title_text: "6. Canaux", description: "Les canaux de distribution", class: "Canaux" },
|
||||||
|
{ projectId: 1, title: 7, title_text: "7. Indicateurs", description: "Les indicateurs clés de performance", class: "Indicateurs" },
|
||||||
|
{ projectId: 1, title: 8, title_text: "8. Coûts", description: "Les coûts associés", class: "Couts" },
|
||||||
|
{ projectId: 1, title: 9, title_text: "9. Revenus", description: "Les sources de revenus", class: "Revenus" }
|
||||||
|
]);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@import "@/components/canvas/style-project.css";
|
||||||
|
|
||||||
|
.canvas {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(10, 1fr);
|
||||||
|
grid-template-rows: repeat(6, 1fr);
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 20px auto;
|
||||||
|
background-color: #fff;
|
||||||
|
position: relative;
|
||||||
|
height: 80vh;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Probleme { grid-column: 1 / 3; grid-row: 1 / 5; padding-top: 20px;}
|
||||||
|
.Segments { grid-column: 9 / 11; grid-row: 1 / 5; padding-top: 20px;}
|
||||||
|
.Valeur { grid-column: 5 / 7; grid-row: 1 / 5; padding-top: 20px;}
|
||||||
|
.Solution { grid-column: 3 / 5; grid-row: 1 / 3; padding-top: 20px;}
|
||||||
|
.Avantage { grid-column: 7 / 9; grid-row: 1 / 3; padding-top: 20px;}
|
||||||
|
.Canaux { grid-column: 7 / 9; grid-row: 3 / 5; padding-top: 20px;}
|
||||||
|
.Indicateurs { grid-column: 3 / 5; grid-row: 3 / 5; padding-top: 20px;}
|
||||||
|
.Couts { grid-column: 1 / 6; grid-row: 5 / 7; padding-top: 20px;}
|
||||||
|
.Revenus { grid-column: 6 / 11; grid-row: 5 / 7; padding-top: 20px;}
|
||||||
|
</style>
|
156
front/MyINPulse-front/src/components/canvas/style-project.css
Normal file
156
front/MyINPulse-front/src/components/canvas/style-project.css
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
flex: 1;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.produit {
|
||||||
|
background-color: #f9e4e4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.marche {
|
||||||
|
background-color: #e4f1f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.valeur {
|
||||||
|
background-color: #f9f4e4;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 5px 0 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 img {
|
||||||
|
height: 80px;
|
||||||
|
margin: 40px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ade {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #e8f5e9;
|
||||||
|
border: 2px solid #4caf50;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ade h3 {
|
||||||
|
color: #2e7d32;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ade p {
|
||||||
|
margin: 10px 0;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-bottom: 2px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
header img {
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header .contact-menu {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-button, .return {
|
||||||
|
padding: 10px 15px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #2196f3;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-button:hover, .return:hover {
|
||||||
|
background-color: #1976d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown styling */
|
||||||
|
.contact-dropdown {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 50px;
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-dropdown button {
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #4caf50;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-dropdown button:hover {
|
||||||
|
background-color: #388e3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.return {
|
||||||
|
background-color: #f44336;
|
||||||
|
}
|
||||||
|
|
||||||
|
.return:hover {
|
||||||
|
background-color: #d32f2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a{
|
||||||
|
color: white;
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 39 KiB |
@ -26,6 +26,52 @@ keycloakService.CallInit(() => {
|
|||||||
console.error(e);
|
console.error(e);
|
||||||
createApp(App).mount("#app");
|
createApp(App).mount("#app");
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
})
|
||||||
|
|
||||||
|
// this shit made by me so i can run the canva vue app
|
||||||
|
//createApp(App).use(router).mount('#app');
|
||||||
|
|
||||||
|
// TODO: fix the comment
|
||||||
|
/*
|
||||||
|
function tokenInterceptor () {
|
||||||
|
axios.interceptors.request.use(config => {
|
||||||
|
const keycloak = useKeycloak()
|
||||||
|
if (keycloak.authenticated) {
|
||||||
|
// Note that this is a simple example.
|
||||||
|
// you should be careful not to leak tokens to third parties.
|
||||||
|
// in this example the token is added to all usage of axios.
|
||||||
|
config.headers.Authorization = `Bearer ${keycloak.token}`
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}, error => {
|
||||||
|
console.error("tokenInterceptor: Rejected")
|
||||||
|
return Promise.reject(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
app.use(VueKeyCloak,{
|
||||||
|
onReady: (keycloak) => {
|
||||||
|
console.log("Ready !")
|
||||||
|
tokenInterceptor()
|
||||||
|
},
|
||||||
|
init: {
|
||||||
|
onLoad: 'login-required',
|
||||||
|
checkLoginIframe: false,
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
config: {
|
||||||
|
realm: 'test',
|
||||||
|
url: 'http://localhost:7080',
|
||||||
|
clientId: 'myinpulse'
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export { store };
|
export { store };
|
||||||
|
14
front/MyINPulse-front/src/plugins/authStore.ts
Normal file
14
front/MyINPulse-front/src/plugins/authStore.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// file: src/plugins/authStore.js
|
||||||
|
|
||||||
|
import { useAuthStore } from "@/stores/authStore.ts";
|
||||||
|
import keycloakService from '@/services/keycloak';
|
||||||
|
// Setup auth store as a plugin so it can be accessed globally in our FE
|
||||||
|
const authStorePlugin = {
|
||||||
|
install(app: any, option: any) {
|
||||||
|
const store = useAuthStore(option.pinia);
|
||||||
|
app.config.globalProperties.$store = store;
|
||||||
|
keycloakService.CallInitStore(store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default authStorePlugin;
|
@ -1,17 +1,30 @@
|
|||||||
import { createRouter, createWebHistory } from "vue-router";
|
import { createRouter, createWebHistory } from "vue-router";
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: "/test",
|
path: '/test',
|
||||||
name: "test",
|
name: 'test',
|
||||||
// route level code-splitting
|
// route level code-splitting
|
||||||
// this generates a separate chunk (About.[hash].js) for this route
|
// this generates a separate chunk (About.[hash].js) for this route
|
||||||
// which is lazy-loaded when the route is visited.
|
// which is lazy-loaded when the route is visited.
|
||||||
component: () => import("../views/testComponent.vue"),
|
component: () => import('../views/testComponent.vue'),
|
||||||
},
|
},
|
||||||
],
|
|
||||||
});
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'Admin-main',
|
||||||
|
component: () => import('../views/AdminMain.vue'),
|
||||||
|
},
|
||||||
|
|
||||||
|
// route pour les canvas (made by adnane), in fact the two vue apps are separated for now
|
||||||
|
{
|
||||||
|
path: '/canvas',
|
||||||
|
name: 'canvas',
|
||||||
|
component: () => import('../views/CanvasView.vue'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
118
front/MyINPulse-front/src/views/AdminMain.vue
Normal file
118
front/MyINPulse-front/src/views/AdminMain.vue
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<Header />
|
||||||
|
<error-wrapper></error-wrapper>
|
||||||
|
<div id="container">
|
||||||
|
<div id="main">
|
||||||
|
<ProjectComp
|
||||||
|
v-for="(project, index) in projects"
|
||||||
|
:key="index"
|
||||||
|
:projectName="project.name"
|
||||||
|
:listName="project.members"
|
||||||
|
:projectLink="project.link"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Agenda :projectRDV="rendezVous" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { callApi } from "@/services/api";
|
||||||
|
|
||||||
|
import Header from "../components/HeaderComponent.vue";
|
||||||
|
import Agenda from "../components/Agenda.vue";
|
||||||
|
import ProjectComp from "../components/ProjectComponent.vue";
|
||||||
|
|
||||||
|
|
||||||
|
const PORT = "8081";
|
||||||
|
const URI = `http://localhost:${PORT}`;
|
||||||
|
|
||||||
|
const projects = ref<{ name: string; link: string; members: string[] }[]>([]);
|
||||||
|
|
||||||
|
const fetchProjects = () => {
|
||||||
|
callApi(
|
||||||
|
`${URI}/admin/projects`,
|
||||||
|
async (response) => {
|
||||||
|
console.log(response);
|
||||||
|
const projectList = response.data;
|
||||||
|
|
||||||
|
const projectPromises = projectList.map((project: any) => {
|
||||||
|
return new Promise(async (resolve) => {
|
||||||
|
callApi(
|
||||||
|
`${URI}/shared/projects/entrepreneurs/${project.idProject}`,
|
||||||
|
(memberResponse) => {
|
||||||
|
const members = memberResponse.data.map((m: any) => m.userName);
|
||||||
|
resolve({
|
||||||
|
name: project.projectName,
|
||||||
|
link: `/project/${project.idProject}`,
|
||||||
|
members,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
// Error fetching members, still resolve with empty members
|
||||||
|
resolve({
|
||||||
|
name: project.projectName,
|
||||||
|
link: `/project/${project.idProject}`,
|
||||||
|
members: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
projects.value = await Promise.all(projectPromises);
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error("Error fetching projects:", error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(fetchProjects);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*const projects = ref([
|
||||||
|
{
|
||||||
|
name: "Projet Alpha",
|
||||||
|
link: "/canvas", // to test
|
||||||
|
members: ["Alice", "Bob", "Charlie"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Projet Beta",
|
||||||
|
link: "./canvas", // to test
|
||||||
|
members: ["David", "Eve", "Frank"],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
*/
|
||||||
|
const rendezVous = ref([
|
||||||
|
{ projectName: "Projet Alpha", date: "2025-03-10", lieu: "P106" },
|
||||||
|
{ projectName: "Projet Beta", date: "2025-04-15", lieu: "Td10" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
#container {
|
||||||
|
margin: 0;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 3fr 1fr; /* Main body takes 3/4, agenda 1/4 */
|
||||||
|
height: 100vh; /* Full viewport height */
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 10px 15px;
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
18
front/MyINPulse-front/src/views/CanvasView.vue
Normal file
18
front/MyINPulse-front/src/views/CanvasView.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<header>
|
||||||
|
<HeaderCanvas />
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1>Page Canvas</h1>
|
||||||
|
<LeanCanvas />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
// @ts-ignore
|
||||||
|
import HeaderCanvas from "../components/canvas/HeaderCanvas.vue";
|
||||||
|
import LeanCanvas from '../components/canvas/LeanCanvas.vue';
|
||||||
|
</script>
|
||||||
|
|
@ -15,11 +15,13 @@ import ErrorModal from "@/components/errorModal.vue";
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.error-wrapper {
|
|
||||||
position: absolute;
|
.error-wrapper{
|
||||||
left: 70%;
|
position: absolute;
|
||||||
//background-color: blue;
|
left: 70%;
|
||||||
height: 100%;
|
/*background-color: blue;*/
|
||||||
width: 30%;
|
height: 100%;
|
||||||
|
width: 30%;
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Reference in New Issue
Block a user