sg-frontend-starter 1.0.0 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +6 -6
- package/.env.example +5 -5
- package/package.json +3 -9
- package/postinstall.js +16 -0
- package/src/components/TelefonEditModal.jsx +124 -124
- package/src/components/TelefonForm.jsx +64 -64
- package/src/components/TelefonGrid.jsx +80 -80
- package/src/services/api.js +83 -83
- package/.degitignore +0 -14
- package/README.md +0 -111
package/.env
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# Mivel ez egy Vite projekt, az environment variableokat VITE_ prefixszel kell kezdeni,
|
|
2
|
-
# hogy azok elérhetőek legyenek!
|
|
3
|
-
VITE_API_BASE_URL=http://localhost:3000/api
|
|
4
|
-
|
|
5
|
-
# API végpontok
|
|
6
|
-
VITE_API_EGY_OLDAL=/gyartok
|
|
1
|
+
# Mivel ez egy Vite projekt, az environment variableokat VITE_ prefixszel kell kezdeni,
|
|
2
|
+
# hogy azok elérhetőek legyenek!
|
|
3
|
+
VITE_API_BASE_URL=http://localhost:3000/api
|
|
4
|
+
|
|
5
|
+
# API végpontok
|
|
6
|
+
VITE_API_EGY_OLDAL=/gyartok
|
|
7
7
|
VITE_API_TOBB_OLDAL=/telefonok
|
package/.env.example
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
VITE_API_BASE_URL=http://localhost:3000/api
|
|
2
|
-
|
|
3
|
-
# API végpontok
|
|
4
|
-
VITE_API_TELEFONOK=/telefonok
|
|
5
|
-
VITE_API_GYARTOK=/gyartok
|
|
1
|
+
VITE_API_BASE_URL=http://localhost:3000/api
|
|
2
|
+
|
|
3
|
+
# API végpontok
|
|
4
|
+
VITE_API_TELEFONOK=/telefonok
|
|
5
|
+
VITE_API_GYARTOK=/gyartok
|
package/package.json
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sg-frontend-starter",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "React Vite starter template",
|
|
3
|
+
"version": "1.0.3",
|
|
5
4
|
"type": "module",
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "https://github.com/mrsoosgabor/frontend-starter.git"
|
|
9
|
-
},
|
|
10
|
-
"author": "Gabor Soos",
|
|
11
|
-
"license": "MIT",
|
|
12
5
|
"scripts": {
|
|
13
6
|
"dev": "vite",
|
|
14
7
|
"build": "vite build",
|
|
15
8
|
"lint": "eslint .",
|
|
16
|
-
"preview": "vite preview"
|
|
9
|
+
"preview": "vite preview",
|
|
10
|
+
"postinstall": "node postinstall.js"
|
|
17
11
|
},
|
|
18
12
|
"dependencies": {
|
|
19
13
|
"bootstrap": "^5.3.8",
|
package/postinstall.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const source = path.join(__dirname, 'node_modules', 'sg-frontend-starter');
|
|
5
|
+
const dest = path.join(__dirname, 'sg-frontend-starter');
|
|
6
|
+
|
|
7
|
+
// Ha létezik a modul a node_modules-ban
|
|
8
|
+
if (fs.existsSync(source)) {
|
|
9
|
+
// Ha már létezik a célhelyen, töröld ki
|
|
10
|
+
if (fs.existsSync(dest)) {
|
|
11
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
12
|
+
}
|
|
13
|
+
// Mozgasd ki a node_modules-ból
|
|
14
|
+
fs.renameSync(source, dest);
|
|
15
|
+
console.log('sg-frontend-starter modul sikeresen áthelyezve');
|
|
16
|
+
}
|
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
2
|
-
|
|
3
|
-
export default function TelefonEditModal({ isOpen, telefon, gyartok, onClose, onSave }) {
|
|
4
|
-
const [editingTelefon, setEditingTelefon] = useState(null);
|
|
5
|
-
|
|
6
|
-
// Frissítjük az editingTelefon state-et, amikor a telefon prop megváltozik
|
|
7
|
-
if (telefon && (!editingTelefon || editingTelefon._id !== telefon._id)) {
|
|
8
|
-
setEditingTelefon({ ...telefon });
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const handleUpdate = async () => {
|
|
12
|
-
if (!editingTelefon._id || !editingTelefon.nev || !editingTelefon.ar) {
|
|
13
|
-
alert("Kérjük, töltse ki az összes mezőt");
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const gyartIdValue = typeof editingTelefon.gyartId === 'object'
|
|
18
|
-
? editingTelefon.gyartId._id
|
|
19
|
-
: editingTelefon.gyartId;
|
|
20
|
-
|
|
21
|
-
if (!gyartIdValue) {
|
|
22
|
-
alert("Kérjük, válasszon egy gyártót");
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const updateData = {
|
|
27
|
-
nev: editingTelefon.nev,
|
|
28
|
-
ar: editingTelefon.ar,
|
|
29
|
-
gyartId: gyartIdValue
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
await onSave(editingTelefon._id, updateData);
|
|
33
|
-
handleClose();
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const handleClose = () => {
|
|
37
|
-
setEditingTelefon(null);
|
|
38
|
-
onClose();
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
if (!isOpen || !editingTelefon) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<div className="modal d-block" style={{ backgroundColor: "rgba(0, 0, 0, 0.5)" }}>
|
|
47
|
-
<div className="modal-dialog modal-dialog-centered">
|
|
48
|
-
<div className="modal-content">
|
|
49
|
-
<div className="modal-header bg-primary text-white">
|
|
50
|
-
<h5 className="modal-title">Telefon módosítása</h5>
|
|
51
|
-
<button
|
|
52
|
-
type="button"
|
|
53
|
-
className="btn-close btn-close-white"
|
|
54
|
-
onClick={handleClose}
|
|
55
|
-
></button>
|
|
56
|
-
</div>
|
|
57
|
-
<div className="modal-body">
|
|
58
|
-
<div>
|
|
59
|
-
<div className="mb-3">
|
|
60
|
-
<label className="form-label">ID:</label>
|
|
61
|
-
<input
|
|
62
|
-
type="text"
|
|
63
|
-
className="form-control"
|
|
64
|
-
value={editingTelefon._id}
|
|
65
|
-
disabled
|
|
66
|
-
/>
|
|
67
|
-
</div>
|
|
68
|
-
<div className="mb-3">
|
|
69
|
-
<label className="form-label">Telefon Neve:</label>
|
|
70
|
-
<input
|
|
71
|
-
type="text"
|
|
72
|
-
className="form-control"
|
|
73
|
-
value={editingTelefon.nev}
|
|
74
|
-
onChange={(e) => setEditingTelefon({...editingTelefon, nev: e.target.value})}
|
|
75
|
-
/>
|
|
76
|
-
</div>
|
|
77
|
-
<div className="mb-3">
|
|
78
|
-
<label className="form-label">Ár (Ft):</label>
|
|
79
|
-
<input
|
|
80
|
-
type="text"
|
|
81
|
-
className="form-control"
|
|
82
|
-
value={editingTelefon.ar}
|
|
83
|
-
onChange={(e) => setEditingTelefon({...editingTelefon, ar: e.target.value})}
|
|
84
|
-
/>
|
|
85
|
-
</div>
|
|
86
|
-
<div className="mb-3">
|
|
87
|
-
<label className="form-label">Gyártó:</label>
|
|
88
|
-
<select
|
|
89
|
-
className="form-select"
|
|
90
|
-
value={editingTelefon.gyartId._id || editingTelefon.gyartId}
|
|
91
|
-
onChange={(e) => {
|
|
92
|
-
const selectedGyarto = gyartok.find(g => g._id === e.target.value);
|
|
93
|
-
setEditingTelefon({...editingTelefon, gyartId: selectedGyarto || e.target.value});
|
|
94
|
-
}}
|
|
95
|
-
>
|
|
96
|
-
<option value="">-- Válasszon gyártót --</option>
|
|
97
|
-
{gyartok.map((gyarto) => (
|
|
98
|
-
<option key={gyarto._id} value={gyarto._id}>{gyarto.nev}</option>
|
|
99
|
-
))}
|
|
100
|
-
</select>
|
|
101
|
-
</div>
|
|
102
|
-
</div>
|
|
103
|
-
</div>
|
|
104
|
-
<div className="modal-footer">
|
|
105
|
-
<button
|
|
106
|
-
type="button"
|
|
107
|
-
className="btn btn-secondary"
|
|
108
|
-
onClick={handleClose}
|
|
109
|
-
>
|
|
110
|
-
Mégse
|
|
111
|
-
</button>
|
|
112
|
-
<button
|
|
113
|
-
type="button"
|
|
114
|
-
className="btn btn-primary"
|
|
115
|
-
onClick={handleUpdate}
|
|
116
|
-
>
|
|
117
|
-
Mentés
|
|
118
|
-
</button>
|
|
119
|
-
</div>
|
|
120
|
-
</div>
|
|
121
|
-
</div>
|
|
122
|
-
</div>
|
|
123
|
-
);
|
|
124
|
-
}
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
export default function TelefonEditModal({ isOpen, telefon, gyartok, onClose, onSave }) {
|
|
4
|
+
const [editingTelefon, setEditingTelefon] = useState(null);
|
|
5
|
+
|
|
6
|
+
// Frissítjük az editingTelefon state-et, amikor a telefon prop megváltozik
|
|
7
|
+
if (telefon && (!editingTelefon || editingTelefon._id !== telefon._id)) {
|
|
8
|
+
setEditingTelefon({ ...telefon });
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const handleUpdate = async () => {
|
|
12
|
+
if (!editingTelefon._id || !editingTelefon.nev || !editingTelefon.ar) {
|
|
13
|
+
alert("Kérjük, töltse ki az összes mezőt");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const gyartIdValue = typeof editingTelefon.gyartId === 'object'
|
|
18
|
+
? editingTelefon.gyartId._id
|
|
19
|
+
: editingTelefon.gyartId;
|
|
20
|
+
|
|
21
|
+
if (!gyartIdValue) {
|
|
22
|
+
alert("Kérjük, válasszon egy gyártót");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const updateData = {
|
|
27
|
+
nev: editingTelefon.nev,
|
|
28
|
+
ar: editingTelefon.ar,
|
|
29
|
+
gyartId: gyartIdValue
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
await onSave(editingTelefon._id, updateData);
|
|
33
|
+
handleClose();
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const handleClose = () => {
|
|
37
|
+
setEditingTelefon(null);
|
|
38
|
+
onClose();
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (!isOpen || !editingTelefon) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div className="modal d-block" style={{ backgroundColor: "rgba(0, 0, 0, 0.5)" }}>
|
|
47
|
+
<div className="modal-dialog modal-dialog-centered">
|
|
48
|
+
<div className="modal-content">
|
|
49
|
+
<div className="modal-header bg-primary text-white">
|
|
50
|
+
<h5 className="modal-title">Telefon módosítása</h5>
|
|
51
|
+
<button
|
|
52
|
+
type="button"
|
|
53
|
+
className="btn-close btn-close-white"
|
|
54
|
+
onClick={handleClose}
|
|
55
|
+
></button>
|
|
56
|
+
</div>
|
|
57
|
+
<div className="modal-body">
|
|
58
|
+
<div>
|
|
59
|
+
<div className="mb-3">
|
|
60
|
+
<label className="form-label">ID:</label>
|
|
61
|
+
<input
|
|
62
|
+
type="text"
|
|
63
|
+
className="form-control"
|
|
64
|
+
value={editingTelefon._id}
|
|
65
|
+
disabled
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
68
|
+
<div className="mb-3">
|
|
69
|
+
<label className="form-label">Telefon Neve:</label>
|
|
70
|
+
<input
|
|
71
|
+
type="text"
|
|
72
|
+
className="form-control"
|
|
73
|
+
value={editingTelefon.nev}
|
|
74
|
+
onChange={(e) => setEditingTelefon({...editingTelefon, nev: e.target.value})}
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
<div className="mb-3">
|
|
78
|
+
<label className="form-label">Ár (Ft):</label>
|
|
79
|
+
<input
|
|
80
|
+
type="text"
|
|
81
|
+
className="form-control"
|
|
82
|
+
value={editingTelefon.ar}
|
|
83
|
+
onChange={(e) => setEditingTelefon({...editingTelefon, ar: e.target.value})}
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
<div className="mb-3">
|
|
87
|
+
<label className="form-label">Gyártó:</label>
|
|
88
|
+
<select
|
|
89
|
+
className="form-select"
|
|
90
|
+
value={editingTelefon.gyartId._id || editingTelefon.gyartId}
|
|
91
|
+
onChange={(e) => {
|
|
92
|
+
const selectedGyarto = gyartok.find(g => g._id === e.target.value);
|
|
93
|
+
setEditingTelefon({...editingTelefon, gyartId: selectedGyarto || e.target.value});
|
|
94
|
+
}}
|
|
95
|
+
>
|
|
96
|
+
<option value="">-- Válasszon gyártót --</option>
|
|
97
|
+
{gyartok.map((gyarto) => (
|
|
98
|
+
<option key={gyarto._id} value={gyarto._id}>{gyarto.nev}</option>
|
|
99
|
+
))}
|
|
100
|
+
</select>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
<div className="modal-footer">
|
|
105
|
+
<button
|
|
106
|
+
type="button"
|
|
107
|
+
className="btn btn-secondary"
|
|
108
|
+
onClick={handleClose}
|
|
109
|
+
>
|
|
110
|
+
Mégse
|
|
111
|
+
</button>
|
|
112
|
+
<button
|
|
113
|
+
type="button"
|
|
114
|
+
className="btn btn-primary"
|
|
115
|
+
onClick={handleUpdate}
|
|
116
|
+
>
|
|
117
|
+
Mentés
|
|
118
|
+
</button>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
import { ErrorMessage, Field, Form, Formik } from "formik";
|
|
2
|
-
|
|
3
|
-
export default function TelefonForm({ gyartok, onSubmit }) {
|
|
4
|
-
return (
|
|
5
|
-
<div className="d-flex justify-content-center pt-5">
|
|
6
|
-
<div style={{ width: "100%", maxWidth: "500px", padding: "30px" }}>
|
|
7
|
-
<h2 className="text-center mb-4 text-white" style={{ backgroundColor: "#667eea", padding: "20px", borderRadius: "10px 10px 0 0" }}>Telefon Felvétel</h2>
|
|
8
|
-
<Formik
|
|
9
|
-
initialValues={{ _id: "", nev: "", ar: "", gyartId: "" }}
|
|
10
|
-
validate={(values) => {
|
|
11
|
-
const errors = {};
|
|
12
|
-
if (!values._id) {
|
|
13
|
-
errors._id = "Kötelező kitölteni";
|
|
14
|
-
}
|
|
15
|
-
if (!values.nev) {
|
|
16
|
-
errors.nev = "Kötelező kitölteni";
|
|
17
|
-
}
|
|
18
|
-
return errors;
|
|
19
|
-
}}
|
|
20
|
-
onSubmit={async (values, { setSubmitting, resetForm }) => {
|
|
21
|
-
console.log("Form data", values);
|
|
22
|
-
await onSubmit(values);
|
|
23
|
-
setSubmitting(false);
|
|
24
|
-
resetForm();
|
|
25
|
-
}}
|
|
26
|
-
>
|
|
27
|
-
{({ isSubmitting }) => (
|
|
28
|
-
<Form className="p-4" style={{ backgroundColor: "#f8f9fa", borderRadius: "0 0 10px 10px", boxShadow: "0 10px 25px rgba(0, 0, 0, 0.1)" }}>
|
|
29
|
-
<div className="mb-3">
|
|
30
|
-
<label htmlFor="_id" className="form-label">ID: </label>
|
|
31
|
-
<Field type="text" name="_id" placeholder="Adjon meg egy egyedi ID-t" className="form-control" />
|
|
32
|
-
<ErrorMessage name="_id" component="div" className="text-danger mt-2" />
|
|
33
|
-
</div>
|
|
34
|
-
<div className="mb-3">
|
|
35
|
-
<label htmlFor="nev" className="form-label">Telefon Neve: </label>
|
|
36
|
-
<Field type="text" name="nev" placeholder="pl. iPhone 15 Pro" className="form-control" />
|
|
37
|
-
<ErrorMessage name="nev" component="div" className="text-danger mt-2" />
|
|
38
|
-
</div>
|
|
39
|
-
<div className="mb-3">
|
|
40
|
-
<label htmlFor="ar" className="form-label">Ár (Ft): </label>
|
|
41
|
-
<Field type="text" name="ar" placeholder="pl. 500000" className="form-control" />
|
|
42
|
-
<ErrorMessage name="ar" component="div" className="text-danger mt-2" />
|
|
43
|
-
</div>
|
|
44
|
-
<div className="mb-3">
|
|
45
|
-
<label htmlFor="gyartId" className="form-label">Gyártó: </label>
|
|
46
|
-
<Field name="gyartId" as="select" className="form-select">
|
|
47
|
-
<option value="">-- Válasszon gyártót --</option>
|
|
48
|
-
{gyartok.map((gyarto) => (
|
|
49
|
-
<option key={gyarto._id} value={gyarto._id}>{gyarto.nev}</option>
|
|
50
|
-
))}
|
|
51
|
-
</Field>
|
|
52
|
-
<ErrorMessage name="gyartId" component="div" className="text-danger mt-2" />
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
<button type="submit" disabled={isSubmitting} className="btn btn-primary w-100 fw-bold">
|
|
56
|
-
{isSubmitting ? "Feldolgozás..." : "Hozzáadás"}
|
|
57
|
-
</button>
|
|
58
|
-
</Form>
|
|
59
|
-
)}
|
|
60
|
-
</Formik>
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
63
|
-
);
|
|
64
|
-
}
|
|
1
|
+
import { ErrorMessage, Field, Form, Formik } from "formik";
|
|
2
|
+
|
|
3
|
+
export default function TelefonForm({ gyartok, onSubmit }) {
|
|
4
|
+
return (
|
|
5
|
+
<div className="d-flex justify-content-center pt-5">
|
|
6
|
+
<div style={{ width: "100%", maxWidth: "500px", padding: "30px" }}>
|
|
7
|
+
<h2 className="text-center mb-4 text-white" style={{ backgroundColor: "#667eea", padding: "20px", borderRadius: "10px 10px 0 0" }}>Telefon Felvétel</h2>
|
|
8
|
+
<Formik
|
|
9
|
+
initialValues={{ _id: "", nev: "", ar: "", gyartId: "" }}
|
|
10
|
+
validate={(values) => {
|
|
11
|
+
const errors = {};
|
|
12
|
+
if (!values._id) {
|
|
13
|
+
errors._id = "Kötelező kitölteni";
|
|
14
|
+
}
|
|
15
|
+
if (!values.nev) {
|
|
16
|
+
errors.nev = "Kötelező kitölteni";
|
|
17
|
+
}
|
|
18
|
+
return errors;
|
|
19
|
+
}}
|
|
20
|
+
onSubmit={async (values, { setSubmitting, resetForm }) => {
|
|
21
|
+
console.log("Form data", values);
|
|
22
|
+
await onSubmit(values);
|
|
23
|
+
setSubmitting(false);
|
|
24
|
+
resetForm();
|
|
25
|
+
}}
|
|
26
|
+
>
|
|
27
|
+
{({ isSubmitting }) => (
|
|
28
|
+
<Form className="p-4" style={{ backgroundColor: "#f8f9fa", borderRadius: "0 0 10px 10px", boxShadow: "0 10px 25px rgba(0, 0, 0, 0.1)" }}>
|
|
29
|
+
<div className="mb-3">
|
|
30
|
+
<label htmlFor="_id" className="form-label">ID: </label>
|
|
31
|
+
<Field type="text" name="_id" placeholder="Adjon meg egy egyedi ID-t" className="form-control" />
|
|
32
|
+
<ErrorMessage name="_id" component="div" className="text-danger mt-2" />
|
|
33
|
+
</div>
|
|
34
|
+
<div className="mb-3">
|
|
35
|
+
<label htmlFor="nev" className="form-label">Telefon Neve: </label>
|
|
36
|
+
<Field type="text" name="nev" placeholder="pl. iPhone 15 Pro" className="form-control" />
|
|
37
|
+
<ErrorMessage name="nev" component="div" className="text-danger mt-2" />
|
|
38
|
+
</div>
|
|
39
|
+
<div className="mb-3">
|
|
40
|
+
<label htmlFor="ar" className="form-label">Ár (Ft): </label>
|
|
41
|
+
<Field type="text" name="ar" placeholder="pl. 500000" className="form-control" />
|
|
42
|
+
<ErrorMessage name="ar" component="div" className="text-danger mt-2" />
|
|
43
|
+
</div>
|
|
44
|
+
<div className="mb-3">
|
|
45
|
+
<label htmlFor="gyartId" className="form-label">Gyártó: </label>
|
|
46
|
+
<Field name="gyartId" as="select" className="form-select">
|
|
47
|
+
<option value="">-- Válasszon gyártót --</option>
|
|
48
|
+
{gyartok.map((gyarto) => (
|
|
49
|
+
<option key={gyarto._id} value={gyarto._id}>{gyarto.nev}</option>
|
|
50
|
+
))}
|
|
51
|
+
</Field>
|
|
52
|
+
<ErrorMessage name="gyartId" component="div" className="text-danger mt-2" />
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<button type="submit" disabled={isSubmitting} className="btn btn-primary w-100 fw-bold">
|
|
56
|
+
{isSubmitting ? "Feldolgozás..." : "Hozzáadás"}
|
|
57
|
+
</button>
|
|
58
|
+
</Form>
|
|
59
|
+
)}
|
|
60
|
+
</Formik>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
2
|
-
import TelefonEditModal from "./TelefonEditModal";
|
|
3
|
-
|
|
4
|
-
export default function TelefonGrid({ mobilok, gyartok, onDelete, onUpdate }) {
|
|
5
|
-
const [editingTelefon, setEditingTelefon] = useState(null);
|
|
6
|
-
const [showModal, setShowModal] = useState(false);
|
|
7
|
-
|
|
8
|
-
const openEditModal = (telefon) => {
|
|
9
|
-
setEditingTelefon({ ...telefon });
|
|
10
|
-
setShowModal(true);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const closeModal = () => {
|
|
14
|
-
setShowModal(false);
|
|
15
|
-
setEditingTelefon(null);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const handleUpdate = async (id, updateData) => {
|
|
19
|
-
await onUpdate(id, updateData);
|
|
20
|
-
closeModal();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<>
|
|
25
|
-
<div className="container mt-5 mb-5">
|
|
26
|
-
<h2 className="mb-4">Telefonok Listája</h2>
|
|
27
|
-
<div className="row g-4">
|
|
28
|
-
{mobilok && mobilok.length > 0 ? (
|
|
29
|
-
mobilok.map((telefon) => {
|
|
30
|
-
return (
|
|
31
|
-
<div key={telefon._id} className="col-md-4 col-sm-6 col-12">
|
|
32
|
-
<div className="card h-100 shadow-sm" style={{ borderTop: "4px solid #667eea" }}>
|
|
33
|
-
<div className="card-body">
|
|
34
|
-
<h5 className="card-title text-primary">{telefon.nev}</h5>
|
|
35
|
-
<p className="card-text mb-2">
|
|
36
|
-
<strong>ID:</strong> {telefon._id}
|
|
37
|
-
</p>
|
|
38
|
-
<p className="card-text mb-2">
|
|
39
|
-
<strong>Ár:</strong> <span className="text-success fw-bold">{telefon.ar} Ft</span>
|
|
40
|
-
</p>
|
|
41
|
-
<p className="card-text mb-0">
|
|
42
|
-
<strong>Gyártó:</strong> {telefon.gyartId ? telefon.gyartId.nev : "Ismeretlen"}
|
|
43
|
-
</p>
|
|
44
|
-
<div className="d-flex gap-2 mt-3">
|
|
45
|
-
<button
|
|
46
|
-
className="btn btn-warning btn-sm flex-grow-1"
|
|
47
|
-
onClick={() => openEditModal(telefon)}
|
|
48
|
-
>
|
|
49
|
-
Módosítás
|
|
50
|
-
</button>
|
|
51
|
-
<button
|
|
52
|
-
className="btn btn-danger btn-sm flex-grow-1"
|
|
53
|
-
onClick={() => onDelete(telefon._id)}
|
|
54
|
-
>
|
|
55
|
-
Törlés
|
|
56
|
-
</button>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
);
|
|
62
|
-
})
|
|
63
|
-
) : (
|
|
64
|
-
<div className="col-12">
|
|
65
|
-
<div className="alert alert-info text-center">Nincsenek telefonok az adatbázisban</div>
|
|
66
|
-
</div>
|
|
67
|
-
)}
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
<TelefonEditModal
|
|
72
|
-
isOpen={showModal}
|
|
73
|
-
telefon={editingTelefon}
|
|
74
|
-
gyartok={gyartok}
|
|
75
|
-
onClose={closeModal}
|
|
76
|
-
onSave={handleUpdate}
|
|
77
|
-
/>
|
|
78
|
-
</>
|
|
79
|
-
);
|
|
80
|
-
}
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import TelefonEditModal from "./TelefonEditModal";
|
|
3
|
+
|
|
4
|
+
export default function TelefonGrid({ mobilok, gyartok, onDelete, onUpdate }) {
|
|
5
|
+
const [editingTelefon, setEditingTelefon] = useState(null);
|
|
6
|
+
const [showModal, setShowModal] = useState(false);
|
|
7
|
+
|
|
8
|
+
const openEditModal = (telefon) => {
|
|
9
|
+
setEditingTelefon({ ...telefon });
|
|
10
|
+
setShowModal(true);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const closeModal = () => {
|
|
14
|
+
setShowModal(false);
|
|
15
|
+
setEditingTelefon(null);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const handleUpdate = async (id, updateData) => {
|
|
19
|
+
await onUpdate(id, updateData);
|
|
20
|
+
closeModal();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
<div className="container mt-5 mb-5">
|
|
26
|
+
<h2 className="mb-4">Telefonok Listája</h2>
|
|
27
|
+
<div className="row g-4">
|
|
28
|
+
{mobilok && mobilok.length > 0 ? (
|
|
29
|
+
mobilok.map((telefon) => {
|
|
30
|
+
return (
|
|
31
|
+
<div key={telefon._id} className="col-md-4 col-sm-6 col-12">
|
|
32
|
+
<div className="card h-100 shadow-sm" style={{ borderTop: "4px solid #667eea" }}>
|
|
33
|
+
<div className="card-body">
|
|
34
|
+
<h5 className="card-title text-primary">{telefon.nev}</h5>
|
|
35
|
+
<p className="card-text mb-2">
|
|
36
|
+
<strong>ID:</strong> {telefon._id}
|
|
37
|
+
</p>
|
|
38
|
+
<p className="card-text mb-2">
|
|
39
|
+
<strong>Ár:</strong> <span className="text-success fw-bold">{telefon.ar} Ft</span>
|
|
40
|
+
</p>
|
|
41
|
+
<p className="card-text mb-0">
|
|
42
|
+
<strong>Gyártó:</strong> {telefon.gyartId ? telefon.gyartId.nev : "Ismeretlen"}
|
|
43
|
+
</p>
|
|
44
|
+
<div className="d-flex gap-2 mt-3">
|
|
45
|
+
<button
|
|
46
|
+
className="btn btn-warning btn-sm flex-grow-1"
|
|
47
|
+
onClick={() => openEditModal(telefon)}
|
|
48
|
+
>
|
|
49
|
+
Módosítás
|
|
50
|
+
</button>
|
|
51
|
+
<button
|
|
52
|
+
className="btn btn-danger btn-sm flex-grow-1"
|
|
53
|
+
onClick={() => onDelete(telefon._id)}
|
|
54
|
+
>
|
|
55
|
+
Törlés
|
|
56
|
+
</button>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
})
|
|
63
|
+
) : (
|
|
64
|
+
<div className="col-12">
|
|
65
|
+
<div className="alert alert-info text-center">Nincsenek telefonok az adatbázisban</div>
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<TelefonEditModal
|
|
72
|
+
isOpen={showModal}
|
|
73
|
+
telefon={editingTelefon}
|
|
74
|
+
gyartok={gyartok}
|
|
75
|
+
onClose={closeModal}
|
|
76
|
+
onSave={handleUpdate}
|
|
77
|
+
/>
|
|
78
|
+
</>
|
|
79
|
+
);
|
|
80
|
+
}
|
package/src/services/api.js
CHANGED
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
|
2
|
-
const ENDPOINTS = {
|
|
3
|
-
TOBB_OLDAL: import.meta.env.VITE_API_TOBB_OLDAL,
|
|
4
|
-
EGY_OLDAL: import.meta.env.VITE_API_EGY_OLDAL,
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Általános API hívás kezelő függvény
|
|
9
|
-
* @param {string} endpoint - Az API végpont (pl. '/telefonok', '/gyartok')
|
|
10
|
-
* @param {object} options - Fetch opciók (method, body, stb.)
|
|
11
|
-
* @returns {Promise} - A válasz JSON formátumban
|
|
12
|
-
*/
|
|
13
|
-
export async function apiCall(endpoint, options = {}) {
|
|
14
|
-
const { method = 'GET', body, headers = {} } = options;
|
|
15
|
-
|
|
16
|
-
const config = {
|
|
17
|
-
method,
|
|
18
|
-
headers: {
|
|
19
|
-
'Content-Type': 'application/json',
|
|
20
|
-
...headers,
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
if (body) {
|
|
25
|
-
config.body = JSON.stringify(body);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
const response = await fetch(`${API_BASE_URL}${endpoint}`, config);
|
|
30
|
-
|
|
31
|
-
const data = await response.json();
|
|
32
|
-
|
|
33
|
-
if (!response.ok) {
|
|
34
|
-
throw new Error(data.message || `HTTP error! status: ${response.status}`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return data;
|
|
38
|
-
} catch (error) {
|
|
39
|
-
console.error('API hívás hiba:', error);
|
|
40
|
-
throw error;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Specifikus API hívások
|
|
45
|
-
export const tobb_oldalAPI = {
|
|
46
|
-
getAll: () => apiCall(ENDPOINTS.TOBB_OLDAL),
|
|
47
|
-
|
|
48
|
-
getById: (id) => apiCall(`${ENDPOINTS.TOBB_OLDAL}/${id}`),
|
|
49
|
-
|
|
50
|
-
create: (data) => apiCall(ENDPOINTS.TOBB_OLDAL, {
|
|
51
|
-
method: 'POST',
|
|
52
|
-
body: data,
|
|
53
|
-
}),
|
|
54
|
-
|
|
55
|
-
update: (id, data) => apiCall(`${ENDPOINTS.TOBB_OLDAL}/${id}`, {
|
|
56
|
-
method: 'PATCH',
|
|
57
|
-
body: data,
|
|
58
|
-
}),
|
|
59
|
-
|
|
60
|
-
delete: (id) => apiCall(`${ENDPOINTS.TOBB_OLDAL}/${id}`, {
|
|
61
|
-
method: 'DELETE',
|
|
62
|
-
}),
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export const egy_oldalAPI = {
|
|
66
|
-
getAll: () => apiCall(ENDPOINTS.EGY_OLDAL),
|
|
67
|
-
|
|
68
|
-
getById: (id) => apiCall(`${ENDPOINTS.EGY_OLDAL}/${id}`),
|
|
69
|
-
|
|
70
|
-
create: (data) => apiCall(ENDPOINTS.EGY_OLDAL, {
|
|
71
|
-
method: 'POST',
|
|
72
|
-
body: data,
|
|
73
|
-
}),
|
|
74
|
-
|
|
75
|
-
update: (id, data) => apiCall(`${ENDPOINTS.EGY_OLDAL}/${id}`, {
|
|
76
|
-
method: 'PATCH',
|
|
77
|
-
body: data,
|
|
78
|
-
}),
|
|
79
|
-
|
|
80
|
-
delete: (id) => apiCall(`${ENDPOINTS.EGY_OLDAL}/${id}`, {
|
|
81
|
-
method: 'DELETE',
|
|
82
|
-
}),
|
|
83
|
-
};
|
|
1
|
+
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
|
2
|
+
const ENDPOINTS = {
|
|
3
|
+
TOBB_OLDAL: import.meta.env.VITE_API_TOBB_OLDAL,
|
|
4
|
+
EGY_OLDAL: import.meta.env.VITE_API_EGY_OLDAL,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Általános API hívás kezelő függvény
|
|
9
|
+
* @param {string} endpoint - Az API végpont (pl. '/telefonok', '/gyartok')
|
|
10
|
+
* @param {object} options - Fetch opciók (method, body, stb.)
|
|
11
|
+
* @returns {Promise} - A válasz JSON formátumban
|
|
12
|
+
*/
|
|
13
|
+
export async function apiCall(endpoint, options = {}) {
|
|
14
|
+
const { method = 'GET', body, headers = {} } = options;
|
|
15
|
+
|
|
16
|
+
const config = {
|
|
17
|
+
method,
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
...headers,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
if (body) {
|
|
25
|
+
config.body = JSON.stringify(body);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const response = await fetch(`${API_BASE_URL}${endpoint}`, config);
|
|
30
|
+
|
|
31
|
+
const data = await response.json();
|
|
32
|
+
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
throw new Error(data.message || `HTTP error! status: ${response.status}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return data;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error('API hívás hiba:', error);
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Specifikus API hívások
|
|
45
|
+
export const tobb_oldalAPI = {
|
|
46
|
+
getAll: () => apiCall(ENDPOINTS.TOBB_OLDAL),
|
|
47
|
+
|
|
48
|
+
getById: (id) => apiCall(`${ENDPOINTS.TOBB_OLDAL}/${id}`),
|
|
49
|
+
|
|
50
|
+
create: (data) => apiCall(ENDPOINTS.TOBB_OLDAL, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
body: data,
|
|
53
|
+
}),
|
|
54
|
+
|
|
55
|
+
update: (id, data) => apiCall(`${ENDPOINTS.TOBB_OLDAL}/${id}`, {
|
|
56
|
+
method: 'PATCH',
|
|
57
|
+
body: data,
|
|
58
|
+
}),
|
|
59
|
+
|
|
60
|
+
delete: (id) => apiCall(`${ENDPOINTS.TOBB_OLDAL}/${id}`, {
|
|
61
|
+
method: 'DELETE',
|
|
62
|
+
}),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const egy_oldalAPI = {
|
|
66
|
+
getAll: () => apiCall(ENDPOINTS.EGY_OLDAL),
|
|
67
|
+
|
|
68
|
+
getById: (id) => apiCall(`${ENDPOINTS.EGY_OLDAL}/${id}`),
|
|
69
|
+
|
|
70
|
+
create: (data) => apiCall(ENDPOINTS.EGY_OLDAL, {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
body: data,
|
|
73
|
+
}),
|
|
74
|
+
|
|
75
|
+
update: (id, data) => apiCall(`${ENDPOINTS.EGY_OLDAL}/${id}`, {
|
|
76
|
+
method: 'PATCH',
|
|
77
|
+
body: data,
|
|
78
|
+
}),
|
|
79
|
+
|
|
80
|
+
delete: (id) => apiCall(`${ENDPOINTS.EGY_OLDAL}/${id}`, {
|
|
81
|
+
method: 'DELETE',
|
|
82
|
+
}),
|
|
83
|
+
};
|
package/.degitignore
DELETED
package/README.md
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
# Telefon Kezelő Alkalmazás - React + Vite
|
|
2
|
-
|
|
3
|
-
Egy modern React alkalmazás telefonok és gyártók kezeléséhez Vite build toolal.
|
|
4
|
-
|
|
5
|
-
## Gyors Telepítés
|
|
6
|
-
|
|
7
|
-
### Degit segítségével (ajánlott)
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npx degit [GitHub-username]/react-starter my-app
|
|
11
|
-
cd my-app
|
|
12
|
-
npm install
|
|
13
|
-
npm run dev
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Helyettesítsd a `[GitHub-username]` helyére a GitHub felhasználónevedet!
|
|
17
|
-
|
|
18
|
-
### Klasszikus klónozás
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
git clone https://github.com/[GitHub-username]/react-starter.git
|
|
22
|
-
cd react-starter
|
|
23
|
-
npm install
|
|
24
|
-
npm run dev
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Telepítési lépések
|
|
28
|
-
|
|
29
|
-
1. **Projekt klónozása/letöltése:**
|
|
30
|
-
```bash
|
|
31
|
-
npx degit [GitHub-username]/react-starter my-app
|
|
32
|
-
cd my-app
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
2. **Függőségek telepítése:**
|
|
36
|
-
```bash
|
|
37
|
-
npm install
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
3. **Environment konfigurálása:**
|
|
41
|
-
```bash
|
|
42
|
-
cp .env.example .env
|
|
43
|
-
```
|
|
44
|
-
Szerkeszd a `.env` fájlt a szükséges API végpontokkal.
|
|
45
|
-
|
|
46
|
-
4. **Fejlesztési szerver indítása:**
|
|
47
|
-
```bash
|
|
48
|
-
npm run dev
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
5. **Gyártáshoz való build:**
|
|
52
|
-
```bash
|
|
53
|
-
npm run build
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Elérhető Parancsok
|
|
57
|
-
|
|
58
|
-
- `npm run dev` - Fejlesztési szerver indítása
|
|
59
|
-
- `npm run build` - Gyártási build készítése
|
|
60
|
-
- `npm run preview` - Build előnézetének megtekintése
|
|
61
|
-
- `npm run lint` - ESLint futtatása
|
|
62
|
-
|
|
63
|
-
## Projekt Struktúra
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
src/
|
|
67
|
-
├── components/
|
|
68
|
-
│ ├── TelefonForm.jsx # Telefon felvételi form
|
|
69
|
-
│ ├── TelefonGrid.jsx # Telefonok grid nézete
|
|
70
|
-
│ └── TelefonEditModal.jsx # Telefon módosítási modal
|
|
71
|
-
├── services/
|
|
72
|
-
│ └── api.js # API hívások kezelése
|
|
73
|
-
├── App.jsx # Főkomponens
|
|
74
|
-
├── main.jsx # Belépési pont
|
|
75
|
-
└── index.css # Globális stílusok
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## Konfiguráció
|
|
79
|
-
|
|
80
|
-
### .env fájl
|
|
81
|
-
|
|
82
|
-
```
|
|
83
|
-
VITE_API_BASE_URL=http://localhost:3000/api
|
|
84
|
-
VITE_API_TELEFONOK=/telefonok
|
|
85
|
-
VITE_API_GYARTOK=/gyartok
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## Szükséges Backend Végpontok
|
|
89
|
-
|
|
90
|
-
Az alkalmazás az alábbi API végpontokat igényli:
|
|
91
|
-
|
|
92
|
-
**Telefonok:**
|
|
93
|
-
- `GET /api/telefonok` - Összes telefon listázása
|
|
94
|
-
- `POST /api/telefonok` - Új telefon felvétele
|
|
95
|
-
- `PATCH /api/telefonok/:id` - Telefon módosítása
|
|
96
|
-
- `DELETE /api/telefonok/:id` - Telefon törlése
|
|
97
|
-
|
|
98
|
-
**Gyártók:**
|
|
99
|
-
- `GET /api/gyartok` - Összes gyártó listázása
|
|
100
|
-
|
|
101
|
-
## Technológiák
|
|
102
|
-
|
|
103
|
-
- **React 18** - UI framework
|
|
104
|
-
- **Vite** - Build tool
|
|
105
|
-
- **Formik** - Form kezelés
|
|
106
|
-
- **Bootstrap** - CSS framework
|
|
107
|
-
- **ESLint** - Kódminőség ellenőrzés
|
|
108
|
-
|
|
109
|
-
## Licensz
|
|
110
|
-
|
|
111
|
-
MIT
|