Skip to content

Commit b78bccf

Browse files
authored
Merge pull request #278 from OceanProtocolEnterprise/feat/stage
Feat/stage
2 parents 0b55131 + 062da88 commit b78bccf

File tree

8 files changed

+400
-19
lines changed

8 files changed

+400
-19
lines changed

src/components/@shared/FormInput/InputElement/EnvironmentSelection/index.module.css

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@
5151
gap: 6px;
5252
}
5353

54+
.titleRow {
55+
display: flex;
56+
align-items: center;
57+
gap: 8px;
58+
}
59+
5460
.title {
5561
font-family: var(--font-family-base);
5662
font-weight: 700;
@@ -70,6 +76,13 @@
7076
display: flex;
7177
gap: 8px;
7278
flex-shrink: 0;
79+
align-items: center;
80+
}
81+
82+
.infoButton {
83+
min-width: auto;
84+
padding: 2px 8px;
85+
font-size: 12px;
7386
}
7487

7588
.freeTag {
@@ -140,3 +153,11 @@
140153
justify-content: space-between;
141154
align-items: center;
142155
}
156+
157+
.infoModalOverlay {
158+
z-index: 2001;
159+
}
160+
161+
.infoModalContent {
162+
max-width: 36rem;
163+
}

src/components/@shared/FormInput/InputElement/EnvironmentSelection/index.tsx

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { ChangeEvent, useEffect, useState } from 'react'
1+
import { ChangeEvent, useState, useMemo } from 'react'
22
import { ComputeEnvironment } from '@oceanprotocol/lib'
33
import Loader from '@shared/atoms/Loader'
44
import { truncateDid } from '@utils/string'
55
import styles from './index.module.css'
66
import SearchSection from '@shared/SearchSection'
77
import StatusTag from '../../../atoms/StatusTag'
88
import Button from '../../../atoms/Button'
9+
import ProviderOwnerInfoModal from '@shared/ProviderOwnerInfoModal'
910

1011
export interface EnvironmentSelectionEnvironment extends ComputeEnvironment {
1112
checked?: boolean
@@ -18,41 +19,37 @@ function Empty({ message }: { message: string }) {
1819
export default function EnvironmentSelection({
1920
environments,
2021
selected,
22+
nodeUrl,
2123
disabled,
2224
onChange
2325
}: {
2426
environments: EnvironmentSelectionEnvironment[]
2527
selected?: string
28+
nodeUrl?: string
2629
disabled?: boolean
2730
onChange?:
2831
| ((value: string) => void)
2932
| ((e: ChangeEvent<HTMLInputElement>) => void)
3033
}): JSX.Element {
3134
const [searchValue, setSearchValue] = useState('')
32-
const [filteredEnvironments, setFilteredEnvironments] = useState<
33-
EnvironmentSelectionEnvironment[]
34-
>([])
35+
const [isInfoModalOpen, setIsInfoModalOpen] = useState(false)
3536

36-
useEffect(() => {
37-
// Combine real environments with mock data
37+
const filteredEnvironments = useMemo(() => {
3838
const realEnvs =
3939
environments && Array.isArray(environments) ? environments : []
4040
const allEnvironments = [...realEnvs]
4141

4242
if (!allEnvironments || allEnvironments.length === 0) {
43-
setFilteredEnvironments([])
44-
return
43+
return []
4544
}
4645

47-
const result = allEnvironments.filter((env) =>
46+
return allEnvironments.filter((env) =>
4847
searchValue !== ''
4948
? env.id.toLowerCase().includes(searchValue.toLowerCase()) ||
5049
(env.description &&
5150
env.description.toLowerCase().includes(searchValue.toLowerCase()))
5251
: true
5352
)
54-
55-
setFilteredEnvironments(result)
5653
}, [environments, searchValue])
5754

5855
const handleEnvironmentSelect = (envId: string) => {
@@ -66,6 +63,10 @@ export default function EnvironmentSelection({
6663
}
6764
}
6865

66+
const handleOpenInfo = () => {
67+
setIsInfoModalOpen(true)
68+
}
69+
6970
return (
7071
<div className={styles.root}>
7172
<SearchSection
@@ -97,9 +98,22 @@ export default function EnvironmentSelection({
9798
>
9899
<div className={styles.cardHeader}>
99100
<div className={styles.titleSection}>
100-
<h3 className={styles.title}>
101-
Environment {index + 1}
102-
</h3>
101+
<div className={styles.titleRow}>
102+
<h3 className={styles.title}>
103+
Environment {index + 1}
104+
</h3>
105+
<Button
106+
style="outlined"
107+
size="small"
108+
className={styles.infoButton}
109+
onClick={(e) => {
110+
e.stopPropagation()
111+
handleOpenInfo()
112+
}}
113+
>
114+
Info
115+
</Button>
116+
</div>
103117
<div className={styles.envId}>
104118
{truncateDid(env.id)}
105119
</div>
@@ -133,6 +147,15 @@ export default function EnvironmentSelection({
133147
</>
134148
)}
135149
</div>
150+
151+
<ProviderOwnerInfoModal
152+
title="Node Owner Info"
153+
isOpen={isInfoModalOpen}
154+
providerUrl={nodeUrl}
155+
overlayClassName={styles.infoModalOverlay}
156+
className={styles.infoModalContent}
157+
onClose={() => setIsInfoModalOpen(false)}
158+
/>
136159
</div>
137160
)
138161
}

src/components/@shared/FormInput/InputElement/Provider/index.module.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@
2626
height: 14px;
2727
margin: 0;
2828
}
29+
2930
.confirmed {
3031
font-weight: var(--font-weight-base);
3132
color: var(--color-success, #5fb359);
3233
}
34+
35+
.infoButton {
36+
min-width: auto;
37+
padding: 2px 10px;
38+
font-size: 12px;
39+
}

src/components/@shared/FormInput/InputElement/Provider/index.tsx

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ import { useChainId } from 'wagmi'
1717
import { customProviderUrl } from 'app.config.cjs'
1818
import CircleErrorIcon from '@images/circle_error.svg'
1919
import CircleCheckIcon from '@images/circle_check.svg'
20+
import ProviderOwnerInfoModal from '@shared/ProviderOwnerInfoModal'
2021

2122
export default function CustomProvider(props: InputProps): ReactElement {
2223
const chainId = useChainId()
2324
const newCancelToken = useCancelToken()
2425
const { initialValues, setFieldError } = useFormikContext<FormPublishData>()
2526
const [field, , helpers] = useField(props.name)
2627
const [isLoading, setIsLoading] = useState(false)
28+
const [isInfoModalOpen, setIsInfoModalOpen] = useState(false)
2729

2830
useEffect(() => {
2931
helpers.setValue({ url: customProviderUrl, valid: true, custom: true })
@@ -119,13 +121,37 @@ export default function CustomProvider(props: InputProps): ReactElement {
119121
handleButtonClick={handleValidation}
120122
isValidated={field?.value?.valid === true}
121123
onReset={handleClear}
124+
additionalAction={
125+
field?.value?.valid === true ? (
126+
<Button
127+
style="outlined"
128+
size="small"
129+
type="button"
130+
className={styles.infoButton}
131+
onClick={(e) => {
132+
e.preventDefault()
133+
setIsInfoModalOpen(true)
134+
}}
135+
>
136+
Info
137+
</Button>
138+
) : null
139+
}
122140
/>
123141

124142
{field?.value?.valid === true ? (
125-
<div className={styles.defaultContainer}>
126-
<CircleCheckIcon />
127-
<div className={styles.confirmed}>File confirmed</div>
128-
</div>
143+
<>
144+
<div className={styles.defaultContainer}>
145+
<CircleCheckIcon />
146+
<div className={styles.confirmed}>File confirmed</div>
147+
</div>
148+
<ProviderOwnerInfoModal
149+
title="Node Owner Info"
150+
isOpen={isInfoModalOpen}
151+
providerUrl={field?.value?.url}
152+
onClose={() => setIsInfoModalOpen(false)}
153+
/>
154+
</>
129155
) : (
130156
<Button
131157
style="text"

src/components/@shared/FormInput/InputElement/URLInput/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ReactElement, useEffect, useState } from 'react'
1+
import { ReactElement, ReactNode, useEffect, useState } from 'react'
22
import Button from '@shared/atoms/Button'
33
import PublishButton from '@shared/PublishButton'
44
import DeleteButton from '@shared/DeleteButton/DeleteButton'
@@ -28,6 +28,7 @@ export interface URLInputProps {
2828
isValidated?: boolean
2929
onReset?: () => void
3030
showResetButton?: boolean
31+
additionalAction?: ReactNode
3132
}
3233

3334
export default function URLInput({
@@ -48,6 +49,7 @@ export default function URLInput({
4849
isValidated = false,
4950
onReset,
5051
showResetButton = true,
52+
additionalAction,
5153
...props
5254
}: URLInputProps): ReactElement {
5355
const [field, meta] = useField(name)
@@ -136,6 +138,8 @@ export default function URLInput({
136138
{showResetButton && (isValidated || showDeleteButton) && (
137139
<DeleteButton onClick={handleReset} />
138140
)}
141+
142+
{additionalAction}
139143
</div>
140144
)}
141145
</InputGroup>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
.modalDescription {
2+
margin: 0 0 8px;
3+
font-size: 15px;
4+
color: var(--clr-slate-70);
5+
word-break: break-word;
6+
}
7+
8+
.modalContent {
9+
width: min(92vw, 62rem);
10+
max-width: min(92vw, 62rem);
11+
}
12+
13+
.scrollArea {
14+
max-height: min(72vh, 58rem);
15+
overflow-y: auto;
16+
overflow-x: hidden;
17+
padding-right: 6px;
18+
}
19+
20+
.ownerInfoList {
21+
display: flex;
22+
flex-direction: column;
23+
gap: 12px;
24+
}
25+
26+
.ownerInfoSection {
27+
display: flex;
28+
flex-direction: column;
29+
gap: 8px;
30+
border: 1px solid var(--ink-alpha-10);
31+
border-radius: 14px;
32+
padding: 12px 14px;
33+
background: var(--brand-white);
34+
box-shadow: 0 2px 8px var(--black-alpha-10);
35+
}
36+
37+
.ownerInfoSectionTitle {
38+
margin: 0;
39+
font-weight: 700;
40+
font-size: 12px;
41+
letter-spacing: 0.02em;
42+
text-transform: uppercase;
43+
color: var(--clr-slate-50);
44+
line-height: 1.2;
45+
}
46+
47+
.ownerInfoSectionBody {
48+
display: flex;
49+
flex-direction: column;
50+
gap: 6px;
51+
}
52+
53+
.ownerInfoItem {
54+
font-size: 16px;
55+
color: var(--clr-slate-70);
56+
line-height: 1.35;
57+
word-break: break-word;
58+
}
59+
60+
.providerUrlCard {
61+
margin-top: 0;
62+
margin-bottom: 16px;
63+
border: 1px solid var(--ink-alpha-10);
64+
border-radius: 14px;
65+
padding: 14px 16px;
66+
background: linear-gradient(
67+
180deg,
68+
var(--navy-alpha-5) 0%,
69+
rgba(10, 75, 112, 0.02) 100%
70+
);
71+
}
72+
73+
.providerUrlLabel {
74+
font-size: 12px;
75+
font-weight: 700;
76+
letter-spacing: 0.02em;
77+
text-transform: uppercase;
78+
color: var(--clr-slate-50);
79+
margin-bottom: 6px;
80+
}
81+
82+
.providerUrlValue {
83+
font-size: 18px;
84+
font-weight: 500;
85+
line-height: 1.3;
86+
color: var(--text-ink);
87+
word-break: break-word;
88+
}
89+
90+
.ownerInfoKey {
91+
font-weight: 700;
92+
color: var(--text-ink);
93+
}
94+
95+
.ownerInfoValue {
96+
color: var(--text-ink);
97+
opacity: 0.75;
98+
}
99+
100+
.ownerInfoLink {
101+
color: var(--ocean-blue-dark, var(--ocean-blue));
102+
text-decoration: underline;
103+
text-underline-offset: 2px;
104+
}

0 commit comments

Comments
 (0)