Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
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
vicotor
frontend
Commits
ea7e636d
Commit
ea7e636d
authored
Dec 19, 2022
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
first two resources and hook
parent
67b6ddab
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
91 additions
and
70 deletions
+91
-70
buildUrl.ts
lib/api/buildUrl.ts
+17
-0
resources.ts
lib/api/resources.ts
+26
-0
useApi.tsx
lib/api/useApi.tsx
+19
-0
useFetch.tsx
lib/hooks/useFetch.tsx
+8
-1
useFetchProfileInfo.tsx
lib/hooks/useFetchProfileInfo.tsx
+4
-22
_app.tsx
pages/_app.tsx
+1
-1
index.ts
pages/api/account/csrf/index.ts
+0
-24
index.ts
pages/api/account/profile/index.ts
+0
-5
proxy.ts
pages/api/proxy.ts
+6
-0
Login.tsx
ui/pages/Login.tsx
+8
-10
Page.tsx
ui/shared/Page/Page.tsx
+2
-7
No files found.
lib/api/buildUrl.ts
0 → 100644
View file @
ea7e636d
import
appConfig
from
'
configs/app/config
'
;
import
{
RESOURCES
}
from
'
./resources
'
;
export
default
function
buildUrl
(
resource
:
keyof
typeof
RESOURCES
,
params
?:
Record
<
string
,
string
>
)
{
const
base
=
appConfig
.
host
===
'
localhost
'
?
appConfig
.
baseUrl
:
appConfig
.
api
.
endpoint
;
const
path
=
appConfig
.
host
===
'
localhost
'
?
'
/proxy
'
+
appConfig
.
api
.
basePath
+
RESOURCES
[
resource
].
path
:
appConfig
.
api
.
basePath
+
RESOURCES
[
resource
].
path
;
const
url
=
new
URL
(
path
,
base
);
params
&&
Object
.
entries
(
params
).
forEach
(([
key
,
value
])
=>
{
url
.
searchParams
.
append
(
key
,
value
);
});
return
url
.
toString
();
}
lib/api/resources.ts
0 → 100644
View file @
ea7e636d
import
type
{
UserInfo
}
from
'
types/api/account
'
;
import
type
{
CsrfData
}
from
'
types/client/account
'
;
export
const
RESOURCES
=
{
user_info
:
{
path
:
'
/api/account/v1/user/info
'
,
queryKey
:
'
user_info
'
,
},
csrf
:
{
path
:
'
/api/account/v1/get_csrf
'
,
queryKey
:
'
csrf
'
,
},
};
export
const
resourceKey
=
(
x
:
keyof
typeof
RESOURCES
)
=>
x
;
export
type
ResourcePayload
<
Q
extends
keyof
typeof
RESOURCES
>
=
Q
extends
'
user_info
'
?
UserInfo
:
Q
extends
'
csrf
'
?
CsrfData
:
never
;
export
interface
ResourceError
{
error
?:
{
status
?:
number
;
statusText
?:
string
;
};
}
lib/api/useApi.tsx
0 → 100644
View file @
ea7e636d
import
type
{
UseQueryOptions
}
from
'
@tanstack/react-query
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
useFetch
from
'
lib/hooks/useFetch
'
;
import
buildUrl
from
'
./buildUrl
'
;
import
type
{
RESOURCES
,
ResourcePayload
,
ResourceError
}
from
'
./resources
'
;
export
default
function
useApi
<
R
extends
keyof
typeof
RESOURCES
>
(
resource
:
R
,
queryOptions
?:
Omit
<
UseQueryOptions
<
unknown
,
ResourceError
,
ResourcePayload
<
R
>>
,
'
queryKey
'
|
'
queryFn
'
>
,
)
{
const
fetch
=
useFetch
();
return
useQuery
<
unknown
,
ResourceError
,
ResourcePayload
<
R
>>
([
resource
],
async
()
=>
{
const
url
=
buildUrl
(
resource
);
return
fetch
(
url
,
{
credentials
:
'
include
'
});
},
queryOptions
);
}
lib/hooks/useFetch.tsx
View file @
ea7e636d
...
...
@@ -4,6 +4,8 @@ import React from 'react';
import
type
{
CsrfData
}
from
'
types/client/account
'
;
import
{
resourceKey
,
RESOURCES
}
from
'
lib/api/resources
'
;
export
interface
ErrorType
<
T
>
{
error
?:
T
;
status
:
Response
[
'
status
'
];
...
...
@@ -18,7 +20,7 @@ interface Params {
export
default
function
useFetch
()
{
const
queryClient
=
useQueryClient
();
const
{
token
}
=
queryClient
.
getQueryData
<
CsrfData
>
([
'
csrf
'
])
||
{};
const
{
token
}
=
queryClient
.
getQueryData
<
CsrfData
>
([
resourceKey
(
'
csrf
'
)
])
||
{};
return
React
.
useCallback
(<
Success
,
Error
>
(path: string, params?: Params): Promise
<
Success
|
ErrorType
<
Error
>
>
=
>
{
const
reqParams
=
{
...
...
@@ -29,6 +31,7 @@ export default function useFetch() {
};
return
fetch
(
path
,
reqParams
).
then
(
response
=>
{
if
(
!
response
.
ok
)
{
const
error
=
{
status
:
response
.
status
,
...
...
@@ -48,6 +51,10 @@ export default function useFetch() {
);
}
else
{
if
(
path
.
includes
(
RESOURCES
.
csrf
.
path
))
{
return
Promise
.
resolve
({
token
:
response
.
headers
.
get
(
'
x-bs-account-csrf
'
)
}
as
Success
);
}
return
response
.
json
()
as
Promise
<
Success
>
;
}
});
...
...
lib/hooks/useFetchProfileInfo.tsx
View file @
ea7e636d
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
type
{
UserInfo
}
from
'
types/api/account
'
;
import
{
QueryKeys
}
from
'
types/client/queries
'
;
import
appConfig
from
'
configs/app/config
'
;
// import * as cookies from 'lib/cookies';
import
useFetch
from
'
lib/hooks/useFetch
'
;
interface
Error
{
error
?:
{
status
?:
number
;
statusText
?:
string
;
};
}
import
useApi
from
'
lib/api/useApi
'
;
import
*
as
cookies
from
'
lib/cookies
'
;
export
default
function
useFetchProfileInfo
()
{
const
fetch
=
useFetch
();
return
useQuery
<
unknown
,
Error
,
UserInfo
>
([
QueryKeys
.
profile
],
async
()
=>
{
const
url
=
new
URL
(
`/proxy/poa/core/api/account/v1/user/info`
,
appConfig
.
baseUrl
);
return
fetch
(
url
.
toString
(),
{
credentials
:
'
include
'
});
},
{
return
useApi
(
'
user_info
'
,
{
refetchOnMount
:
false
,
//
enabled: Boolean(cookies.get(cookies.NAMES.API_TOKEN)),
enabled
:
Boolean
(
cookies
.
get
(
cookies
.
NAMES
.
API_TOKEN
)),
});
}
pages/_app.tsx
View file @
ea7e636d
...
...
@@ -23,7 +23,7 @@ function MyApp({ Component, pageProps }: AppProps) {
refetchOnWindowFocus
:
false
,
retry
:
(
failureCount
,
_error
)
=>
{
const
error
=
_error
as
ErrorType
<
{
status
:
number
}
>
;
const
status
=
error
?.
error
?.
status
;
const
status
=
error
?.
status
||
error
?.
error
?.
status
;
if
(
status
&&
status
>=
400
&&
status
<
500
)
{
// don't do retry for client error responses
return
false
;
...
...
pages/api/account/csrf/index.ts
deleted
100644 → 0
View file @
67b6ddab
import
type
{
NextApiRequest
,
NextApiResponse
}
from
'
next
'
;
import
fetchFactory
from
'
lib/api/fetch
'
;
import
getUrlWithNetwork
from
'
lib/api/getUrlWithNetwork
'
;
import
{
httpLogger
}
from
'
lib/api/logger
'
;
export
default
async
function
csrfHandler
(
_req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
httpLogger
(
_req
,
res
);
const
url
=
getUrlWithNetwork
(
_req
,
`/api/account/v1/get_csrf`
);
const
fetch
=
fetchFactory
(
_req
);
const
response
=
await
fetch
(
url
);
if
(
response
.
status
===
200
)
{
const
token
=
response
.
headers
.
get
(
'
x-bs-account-csrf
'
);
res
.
status
(
200
).
json
({
token
});
return
;
}
const
responseError
=
{
statusText
:
response
.
statusText
,
status
:
response
.
status
};
httpLogger
.
logger
.
error
({
err
:
responseError
,
url
:
_req
.
url
});
res
.
status
(
500
).
json
(
responseError
);
}
pages/api/account/profile/index.ts
deleted
100644 → 0
View file @
67b6ddab
import
handler
from
'
lib/api/handler
'
;
const
profileHandler
=
handler
(()
=>
'
/account/v1/user/info
'
,
[
'
GET
'
]);
export
default
profileHandler
;
pages/api/proxy.ts
View file @
ea7e636d
...
...
@@ -15,6 +15,12 @@ const handler = async(_req: NextApiRequest, res: NextApiResponse) => {
_pickBy
(
_pick
(
_req
,
[
'
body
'
,
'
method
'
]),
Boolean
),
);
// don't think that we have to proxy all headers, so pick only necessary ones
[
'
x-bs-account-csrf
'
].
forEach
((
headerName
)
=>
{
const
headerValue
=
response
.
headers
.
get
(
headerName
);
headerValue
&&
res
.
setHeader
(
headerName
,
headerValue
);
});
res
.
status
(
response
.
status
).
send
(
response
.
body
);
};
...
...
ui/pages/Login.tsx
View file @
ea7e636d
import
{
VStack
,
Textarea
,
Button
,
Alert
,
AlertTitle
,
AlertDescription
,
Link
,
Code
,
Flex
,
Box
}
from
'
@chakra-ui/react
'
;
import
{
VStack
,
Textarea
,
Button
,
Alert
,
AlertTitle
,
AlertDescription
,
Code
,
Flex
,
Box
}
from
'
@chakra-ui/react
'
;
import
*
as
Sentry
from
'
@sentry/react
'
;
import
type
{
ChangeEvent
}
from
'
react
'
;
import
React
from
'
react
'
;
...
...
@@ -47,8 +47,6 @@ const Login = () => {
});
},
[
toast
,
token
]);
const
prodUrl
=
'
https://blockscout.com/poa/core
'
;
const
handleNumIncrement
=
React
.
useCallback
(()
=>
{
for
(
let
index
=
0
;
index
<
5
;
index
++
)
{
setNum
(
5
);
...
...
@@ -58,19 +56,15 @@ const Login = () => {
return
(
<
Page
>
<
VStack
gap=
{
4
}
alignItems=
"flex-start"
maxW=
"1000px"
>
<
PageTitle
text=
"Vercel page"
/>
<
Flex
columnGap=
{
2
}
alignItems=
"center"
>
<
Box
w=
"50px"
textAlign=
"center"
>
{
num
}
</
Box
>
<
Button
onClick=
{
handleNumIncrement
}
size=
"sm"
>
add
</
Button
>
</
Flex
>
<
PageTitle
text=
"Login page 😂"
/>
{
isFormVisible
&&
(
<>
<
Alert
status=
"error"
flexDirection=
"column"
alignItems=
"flex-start"
>
<
AlertTitle
fontSize=
"md"
>
!!! Temporary solution for authentication !!!
!!! Temporary solution for authentication
on localhost
!!!
</
AlertTitle
>
<
AlertDescription
mt=
{
3
}
>
To Sign in go to
<
Link
href=
{
prodUrl
}
target=
"_blank"
>
{
prodUrl
}
</
Link
>
first, sign in there, copy obtained API token from cookie
To Sign in go to
production instance
first, sign in there, copy obtained API token from cookie
<
Code
ml=
{
1
}
>
{
cookies
.
NAMES
.
API_TOKEN
}
</
Code
>
and paste it in the form below. After submitting the form you should be successfully
authenticated in current environment
</
AlertDescription
>
...
...
@@ -80,6 +74,10 @@ const Login = () => {
</>
)
}
<
Button
colorScheme=
"red"
onClick=
{
checkSentry
}
>
Check Sentry
</
Button
>
<
Flex
columnGap=
{
2
}
alignItems=
"center"
>
<
Box
w=
"50px"
textAlign=
"center"
>
{
num
}
</
Box
>
<
Button
onClick=
{
handleNumIncrement
}
size=
"sm"
>
add
</
Button
>
</
Flex
>
</
VStack
>
</
Page
>
);
...
...
ui/shared/Page/Page.tsx
View file @
ea7e636d
import
{
Flex
}
from
'
@chakra-ui/react
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
React
from
'
react
'
;
import
{
QueryKeys
}
from
'
types/client/queries
'
;
import
useApi
from
'
lib/api/useApi
'
;
import
*
as
cookies
from
'
lib/cookies
'
;
import
useFetch
from
'
lib/hooks/useFetch
'
;
import
AppError
from
'
ui/shared/AppError/AppError
'
;
import
ErrorBoundary
from
'
ui/shared/ErrorBoundary
'
;
import
PageContent
from
'
ui/shared/Page/PageContent
'
;
...
...
@@ -25,9 +22,7 @@ const Page = ({
hideMobileHeaderOnScrollDown
,
isHomePage
,
}:
Props
)
=>
{
const
fetch
=
useFetch
();
useQuery
<
unknown
,
unknown
,
unknown
>
([
QueryKeys
.
csrf
],
async
()
=>
await
fetch
(
'
/node-api/account/csrf
'
),
{
useApi
(
'
csrf
'
,
{
enabled
:
Boolean
(
cookies
.
get
(
cookies
.
NAMES
.
API_TOKEN
)),
});
...
...
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