Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
A
aphp1_75classwork
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Egor Kremnev
aphp1_75classwork
Commits
3ced9e8e
Commit
3ced9e8e
authored
Jul 25, 2023
by
Egor Kremnev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
end crud article in frontend
parent
3d29669b
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
327 additions
and
18 deletions
+327
-18
PassportAuthController.php
api/app/Http/Controllers/Api/PassportAuthController.php
+9
-2
ArticlesPageTable.jsx
...nd/src/components/ArticlesPageTable/ArticlesPageTable.jsx
+7
-2
Item.jsx
frontend/src/components/ArticlesPageTable/Item/Item.jsx
+4
-6
Navbar.jsx
frontend/src/components/common/Navbar/Navbar.jsx
+2
-1
ArticleEdit.jsx
frontend/src/containers/Article/ArticleEdit/ArticleEdit.jsx
+33
-0
ArticleForm.jsx
frontend/src/containers/Article/ArticleForm/ArticleForm.jsx
+102
-0
ArticleList.css
frontend/src/containers/Article/ArticleList/ArticleList.css
+0
-0
ArticleList.jsx
frontend/src/containers/Article/ArticleList/ArticleList.jsx
+59
-0
ArticleShow.jsx
frontend/src/containers/Article/ArticleShow/ArticleShow.jsx
+48
-0
Login.jsx
frontend/src/containers/Auth/Login/Login.jsx
+5
-5
PrivateRoute.jsx
frontend/src/routes/PrivateRoute.jsx
+11
-0
router.js
frontend/src/routes/router.js
+18
-2
request.js
frontend/src/services/request.js
+29
-0
No files found.
api/app/Http/Controllers/Api/PassportAuthController.php
View file @
3ced9e8e
...
...
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api;
use
App\Http\Controllers\Controller
;
use
App\Http\Requests\Api\RegisterRequest
;
use
App\Http\Resources\Api\UserResource
;
use
App\Models\User
;
use
Illuminate\Http\JsonResponse
;
use
Illuminate\Http\Request
;
...
...
@@ -23,7 +24,10 @@ class PassportAuthController extends Controller
]);
return
response
()
->
json
(
[
'token'
=>
$user
->
createToken
(
'LaravelAuthApp'
)
->
accessToken
],
[
'token'
=>
$user
->
createToken
(
'LaravelAuthApp'
)
->
accessToken
,
'user'
=>
new
UserResource
(
$user
)
],
201
);
}
...
...
@@ -36,7 +40,10 @@ class PassportAuthController extends Controller
{
if
(
auth
()
->
attempt
(
$request
->
only
([
'email'
,
'password'
])))
{
return
response
()
->
json
([
'token'
=>
auth
()
->
user
()
->
createToken
(
'LaravelAuthApp'
)
->
accessToken
]);
->
json
([
'token'
=>
auth
()
->
user
()
->
createToken
(
'LaravelAuthApp'
)
->
accessToken
,
'user'
=>
new
UserResource
(
auth
()
->
user
())
]);
}
return
response
()
->
json
([
'error'
=>
'Unauthorised'
],
401
);
...
...
frontend/src/components/ArticlesPageTable/ArticlesPageTable.jsx
View file @
3ced9e8e
...
...
@@ -2,7 +2,7 @@ import {Table} from "semantic-ui-react";
import
React
from
"react"
;
import
Item
from
"./Item/Item"
;
const
ArticlesPageTable
=
({
articles
})
=>
{
const
ArticlesPageTable
=
({
articles
,
isLoading
,
onDeleteHandler
})
=>
{
return
<
div
>
<
Table
>
<
thead
>
...
...
@@ -15,7 +15,12 @@ const ArticlesPageTable = ({articles}) => {
</
tr
>
</
thead
>
<
tbody
>
{
articles
.
map
(
article
=>
<
Item
article=
{
article
}
key=
{
article
.
id
}
/>)
}
{
articles
.
map
(
article
=>
<
Item
article=
{
article
}
key=
{
article
.
id
}
isLoading=
{
isLoading
}
onDeleteHandler=
{
onDeleteHandler
}
/>)
}
</
tbody
>
</
Table
>
</
div
>;
...
...
frontend/src/components/ArticlesPageTable/Item/Item.jsx
View file @
3ced9e8e
...
...
@@ -2,7 +2,7 @@ import {Button} from "semantic-ui-react";
import
{
Link
}
from
"react-router-dom"
;
import
React
from
"react"
;
const
Item
=
({
article
})
=>
{
const
Item
=
({
article
,
isLoading
,
onDeleteHandler
})
=>
{
return
<
tr
>
<
td
>
{
article
.
id
}
</
td
>
<
td
>
{
article
.
title
}
</
td
>
...
...
@@ -10,13 +10,11 @@ const Item = ({article}) => {
<
td
>
{
article
.
user
.
name
}
</
td
>
<
td
>
<
Button
.
Group
>
<
Button
color=
"blue"
as=
{
Link
}
to=
{
`/articles/${article.id}`
}
>
Show
</
Button
>
<
Button
color=
"blue"
as=
{
Link
}
to=
{
`/articles/${article.id}`
}
>
Show
</
Button
>
<
Button
.
Or
/>
<
Button
color=
"orange"
>
Edit
</
Button
>
<
Button
color=
"orange"
as=
{
Link
}
to=
{
`/articles/${article.id}/update`
}
>
Edit
</
Button
>
<
Button
.
Or
/>
<
Button
color=
"red"
>
Delete
</
Button
>
<
Button
loading=
{
isLoading
}
color=
"red"
onClick=
{
()
=>
onDeleteHandler
(
article
.
id
)
}
>
Delete
</
Button
>
</
Button
.
Group
>
</
td
>
</
tr
>;
...
...
frontend/src/components/common/Navbar/Navbar.jsx
View file @
3ced9e8e
...
...
@@ -23,7 +23,8 @@ const Navbar = () => {
const
handleLogOut
=
(
e
)
=>
{
setState
({
isAuth
:
false
,
activeItem
:
'logout'
});
localStorage
.
removeItem
(
'token'
);
navigate
(
"/login"
);
localStorage
.
removeItem
(
'user'
);
return
navigate
(
"/login"
);
};
const
authButtons
=
()
=>
{
...
...
frontend/src/containers/Article/ArticleEdit/ArticleEdit.jsx
0 → 100644
View file @
3ced9e8e
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
get
}
from
"../../../services/request"
;
import
{
API_BASE_URL
}
from
"../../../config"
;
import
{
Message
}
from
'semantic-ui-react'
;
import
ArticleForm
from
"../ArticleForm/ArticleForm"
;
import
{
useParams
}
from
"react-router-dom"
;
const
ArticleEdit
=
()
=>
{
const
[
state
,
setState
]
=
useState
({
article
:
null
,
isLoading
:
false
,
});
const
{
id
}
=
useParams
();
useEffect
(()
=>
{
const
token
=
localStorage
.
getItem
(
'token'
);
if
(
!
state
.
article
)
{
setState
(
prevState
=>
({...
prevState
,
isLoading
:
true
}));
get
(
API_BASE_URL
+
`/articles/
${
id
}
`
,
token
)
.
then
(
data
=>
setState
(
prevState
=>
({...
prevState
,
article
:
data
.
data
,
isLoading
:
false
})));
}
},
[
id
]);
return
(
<
div
>
{
state
.
isLoading
&&
<
Message
info
header=
"Loading article..."
/>
}
{
state
.
article
&&
<
ArticleForm
article=
{
state
.
article
}
/>
}
</
div
>
);
};
export
default
ArticleEdit
;
frontend/src/containers/Article/ArticleForm/ArticleForm.jsx
0 → 100644
View file @
3ced9e8e
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Button
,
Form
,
Message
,
TextArea
}
from
'semantic-ui-react'
;
import
{
API_BASE_URL
}
from
"../../../config"
;
import
{
post
,
put
}
from
"../../../services/request"
;
import
{
useNavigate
}
from
'react-router-dom'
;
import
Errors
from
"../../../components/Errors/Errors"
;
const
ArticleForm
=
({
article
})
=>
{
const
[
state
,
setState
]
=
useState
(
{
article
,
title
:
null
,
content
:
null
,
isLoading
:
false
,
errorMessage
:
null
,
errors
:
null
,
error
:
null
});
const
navigate
=
useNavigate
();
const
handleSubmit
=
(
e
)
=>
{
e
.
preventDefault
();
setState
(
prevState
=>
({...
prevState
,
isLoading
:
true
}));
const
token
=
localStorage
.
getItem
(
'token'
);
const
user
=
JSON
.
parse
(
localStorage
.
getItem
(
'user'
));
const
data
=
{
title
:
state
.
title
,
content
:
state
.
content
,
user_id
:
user
.
id
};
if
(
state
.
article
)
{
put
(
API_BASE_URL
+
`/articles/
${
state
.
article
.
id
}
`
,
data
,
token
)
.
then
(
response
=>
{
if
(
Object
.
keys
(
response
).
includes
(
'data'
))
{
return
navigate
(
'/articles'
);
}
else
if
(
Object
.
keys
(
response
).
includes
(
'error'
))
{
setState
(
prevState
=>
({...
prevState
,
error
:
response
.
error
}));
}
else
{
setState
(
prevState
=>
({...
prevState
,
error
:
response
.
error
,
errorMessage
:
response
.
message
,}));
}
});
}
else
{
post
(
API_BASE_URL
+
"/articles"
,
data
,
token
)
.
then
(
response
=>
{
if
(
Object
.
keys
(
response
).
includes
(
'data'
))
{
return
navigate
(
'/articles'
);
}
else
if
(
Object
.
keys
(
response
).
includes
(
'error'
))
{
setState
(
prevState
=>
({...
prevState
,
error
:
response
.
error
}));
}
else
{
setState
(
prevState
=>
({...
prevState
,
error
:
response
.
error
,
errorMessage
:
response
.
message
,}));
}
});
}
setState
(
prevState
=>
({...
prevState
,
isLoading
:
false
}));
};
useEffect
(()
=>
{
if
(
article
)
{
setState
(
prevState
=>
({
...
prevState
,
title
:
article
.
title
,
content
:
article
.
content
}));
}
},
[
article
]);
const
onChangeInputHandler
=
e
=>
{
const
{
name
,
value
}
=
e
.
currentTarget
;
setState
(
prevState
=>
({
...
prevState
,
[
name
]:
value
,
errors
:
null
}));
};
return
(
<
div
>
{
state
.
error
&&
<
Message
negative
><
Message
.
Header
>
{
this
.
state
.
error
}
</
Message
.
Header
></
Message
>
}
{
state
.
errors
&&
<
Errors
errors=
{
state
.
errors
}
errorMessage=
{
state
.
errorMessage
}
/>
}
<
Form
>
<
Form
.
Field
>
<
label
>
Title
</
label
>
<
input
type=
"text"
placeholder=
'Title'
value=
{
state
.
title
||
''
}
name=
'title'
onChange=
{
onChangeInputHandler
}
/>
</
Form
.
Field
>
<
Form
.
Field
>
<
label
>
Content
</
label
>
<
TextArea
value=
{
state
.
content
||
''
}
placeholder=
'Content'
style=
{
{
minHeight
:
100
}
}
name=
'content'
onChange=
{
onChangeInputHandler
}
/>
</
Form
.
Field
>
<
Button
loading=
{
state
.
isLoading
}
type=
'submit'
onClick=
{
handleSubmit
}
>
{
state
.
article
?
'Edit article'
:
'Create article'
}
</
Button
>
</
Form
>
</
div
>
);
};
export
default
ArticleForm
;
frontend/src/containers/Article
sPage/ArticlesPage
.css
→
frontend/src/containers/Article
/ArticleList/ArticleList
.css
View file @
3ced9e8e
File moved
frontend/src/containers/Article
sPage/ArticlesPage
.jsx
→
frontend/src/containers/Article
/ArticleList/ArticleList
.jsx
View file @
3ced9e8e
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
'./Article
sPage
.css'
;
import
{
API_BASE_URL
}
from
"../../config"
;
import
{
Header
,
Message
}
from
"semantic-ui-react"
;
import
ArticlesPageTable
from
"../../components/ArticlesPageTable/ArticlesPageTable"
;
import
{
useNavigate
}
from
"react-router-dom"
;
import
{
get
}
from
"
../../services/request"
;
const
Article
sPage
=
()
=>
{
import
'./Article
List
.css'
;
import
{
API_BASE_URL
}
from
"../../
../
config"
;
import
{
Button
,
Header
,
Message
}
from
"semantic-ui-react"
;
import
ArticlesPageTable
from
"../../
../
components/ArticlesPageTable/ArticlesPageTable"
;
import
{
Link
}
from
"react-router-dom"
;
import
{
get
,
remove
}
from
"../
../../services/request"
;
const
Article
List
=
()
=>
{
const
[
state
,
setState
]
=
useState
({
articles
:
null
,
isLoading
:
false
});
const
navigate
=
useNavigate
();
const
getArticles
=
()
=>
{
const
token
=
localStorage
.
getItem
(
'token'
);
if
(
!
token
)
navigate
(
'/login'
);
try
{
setState
(
prevState
=>
({...
prevState
,
isLoading
:
true
}));
const
response
=
get
(
API_BASE_URL
+
"/articles"
,
token
);
...
...
@@ -30,20 +26,34 @@ const ArticlesPage = () => {
}
useEffect
(()
=>
{
const
token
=
localStorage
.
getItem
(
'token'
);
if
(
!
token
)
navigate
(
'/login'
);
if
(
!
state
.
articles
)
getArticles
();
},
[]);
const
handleDelete
=
(
articleId
)
=>
{
setState
(
prevState
=>
({...
prevState
,
isLoading
:
true
}));
const
token
=
localStorage
.
getItem
(
'token'
);
remove
(
API_BASE_URL
+
`/articles/
${
articleId
}
`
,
token
)
.
then
(
getArticles
)
.
finally
(()
=>
setState
(
prevState
=>
({...
prevState
,
isLoading
:
false
})));
};
return
(
<
div
>
<
Header
as=
"h1"
>
Articles
</
Header
>
<
div
>
<
Button
color=
"blue"
as=
{
Link
}
to=
'/articles/create'
>
Create article
</
Button
>
</
div
>
{
state
.
isLoading
&&
<
Message
info
header=
"Loading articles..."
/>
}
{
state
.
articles
&&
<
ArticlesPageTable
articles=
{
state
.
articles
}
/>
}
{
state
.
articles
&&
<
ArticlesPageTable
articles=
{
state
.
articles
}
isLoading=
{
state
.
isLoading
}
onDeleteHandler=
{
handleDelete
}
/>
}
</
div
>
);
};
export
default
Article
sPage
;
export
default
Article
List
;
frontend/src/containers/Article/ArticleShow/ArticleShow.jsx
0 → 100644
View file @
3ced9e8e
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
get
}
from
"../../../services/request"
;
import
{
API_BASE_URL
}
from
"../../../config"
;
import
{
Item
,
Message
,
Header
}
from
'semantic-ui-react'
;
import
{
useParams
}
from
"react-router-dom"
;
const
ArticleShow
=
()
=>
{
const
[
state
,
setState
]
=
useState
({
article
:
null
,
isLoading
:
false
,
});
const
{
id
}
=
useParams
();
useEffect
(()
=>
{
const
token
=
localStorage
.
getItem
(
'token'
);
if
(
!
state
.
article
)
{
setState
(
prevState
=>
({...
prevState
,
isLoading
:
true
}));
get
(
API_BASE_URL
+
`/articles/
${
id
}
`
,
token
)
.
then
(
data
=>
setState
(
prevState
=>
({...
prevState
,
article
:
data
.
data
,
isLoading
:
false
})));
}
},
[
id
]);
return
(
<
div
>
{
state
.
isLoading
&&
<
Message
info
header=
"Loading article..."
/>
}
{
state
.
article
&&
<
div
>
<
Header
as=
"h1"
>
Article -
{
state
.
article
.
title
}
</
Header
>
<
Item
>
<
Item
.
Content
>
<
Item
.
Header
as=
'h3'
>
{
state
.
article
.
title
}
</
Item
.
Header
>
<
Item
.
Description
>
<
p
>
{
state
.
article
.
content
}
</
p
>
</
Item
.
Description
>
</
Item
.
Content
>
</
Item
>
</
div
>
}
</
div
>
);
};
export
default
ArticleShow
;
frontend/src/containers/Auth/Login/Login.jsx
View file @
3ced9e8e
...
...
@@ -29,11 +29,12 @@ const Login = () => {
email
:
state
.
email
,
password
:
state
.
password
};
const
res
=
post
(
API_BASE_URL
+
"/login"
,
data
);
res
.
then
(
response
=>
{
post
(
API_BASE_URL
+
"/login"
,
data
)
.
then
(
response
=>
{
if
(
Object
.
keys
(
response
).
includes
(
'token'
))
{
localStorage
.
setItem
(
'token'
,
response
.
token
);
navigate
(
'/'
);
localStorage
.
setItem
(
'user'
,
JSON
.
stringify
(
response
.
user
));
return
navigate
(
'/'
);
}
else
if
(
Object
.
keys
(
response
).
includes
(
'error'
))
{
setState
(
prevState
=>
({...
prevState
,
error
:
response
.
error
}));
}
...
...
@@ -44,8 +45,7 @@ const Login = () => {
errors
:
response
.
errors
,
isLoading
:
false
}));
}
);
});
};
const
onChangeInputHandler
=
e
=>
{
...
...
frontend/src/routes/PrivateRoute.jsx
0 → 100644
View file @
3ced9e8e
import
{
Navigate
}
from
"react-router-dom"
;
import
React
from
"react"
;
const
PrivateRoute
=
({
component
})
=>
{
const
token
=
localStorage
.
getItem
(
'token'
);
const
user
=
JSON
.
parse
(
localStorage
.
getItem
(
'user'
));
return
token
&&
user
?
component
:
<
Navigate
to=
"/login"
/>;
};
export
default
PrivateRoute
;
frontend/src/routes/router.js
View file @
3ced9e8e
...
...
@@ -3,9 +3,13 @@ import HomePage from "../components/HomePage/HomePage";
import
Root
from
"./Root"
;
import
React
from
'react'
;
import
Error
from
"./Error"
;
import
Article
sPage
from
"../containers/ArticlesPage/ArticlesPage
"
;
import
Article
List
from
"../containers/Article/ArticleList/ArticleList
"
;
import
Register
from
"../containers/Auth/Register/Register"
;
import
Login
from
"../containers/Auth/Login/Login"
;
import
ArticleForm
from
"../containers/Article/ArticleForm/ArticleForm"
;
import
ArticleEdit
from
"../containers/Article/ArticleEdit/ArticleEdit"
;
import
ArticleShow
from
"../containers/Article/ArticleShow/ArticleShow"
;
import
PrivateRoute
from
"./PrivateRoute"
;
const
router
=
createBrowserRouter
([
{
...
...
@@ -19,7 +23,19 @@ const router = createBrowserRouter([
},
{
path
:
'/articles'
,
element
:
<
ArticlesPage
/>
element
:
<
PrivateRoute
component
=
{
<
ArticleList
/>
}
/
>
},
{
path
:
'/articles/create'
,
element
:
<
PrivateRoute
component
=
{
<
ArticleForm
/>
}
/
>
},
{
path
:
'/articles/:id'
,
element
:
<
PrivateRoute
component
=
{
<
ArticleShow
/>
}
/
>
},
{
path
:
'/articles/:id/update'
,
element
:
<
PrivateRoute
component
=
{
<
ArticleEdit
/>
}
/
>
},
{
path
:
'/register'
,
...
...
frontend/src/services/request.js
View file @
3ced9e8e
...
...
@@ -33,3 +33,32 @@ export function post(url, data, token) {
}
).
then
(
playWithResponsePromise
);
}
export
function
remove
(
url
,
token
)
{
return
fetch
(
url
,
{
method
:
'DELETE'
,
headers
:
{
'Accept'
:
'application/json'
,
'Content-type'
:
'application/json'
,
...
token
&&
{
'Authorization'
:
'Bearer '
+
token
}
}
}
);
}
export
function
put
(
url
,
data
,
token
)
{
return
fetch
(
url
,
{
method
:
'PUT'
,
body
:
JSON
.
stringify
(
data
),
headers
:
{
'Accept'
:
'application/json'
,
'Content-type'
:
'application/json'
,
...
token
&&
{
'Authorization'
:
'Bearer '
+
token
}
}
}
).
then
(
playWithResponsePromise
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment