serene-core-client 0.1.1
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/dist/index.d.ts +36 -0
- package/dist/index.js +36 -0
- package/dist/src/apollo/access.d.ts +1 -0
- package/dist/src/apollo/access.js +9 -0
- package/dist/src/apollo/mailing-lists.d.ts +2 -0
- package/dist/src/apollo/mailing-lists.js +33 -0
- package/dist/src/apollo/quotas.d.ts +1 -0
- package/dist/src/apollo/quotas.js +21 -0
- package/dist/src/apollo/techs.d.ts +1 -0
- package/dist/src/apollo/techs.js +15 -0
- package/dist/src/apollo/tips.d.ts +3 -0
- package/dist/src/apollo/tips.js +45 -0
- package/dist/src/apollo/user-preferences.d.ts +2 -0
- package/dist/src/apollo/user-preferences.js +32 -0
- package/dist/src/apollo/users.d.ts +6 -0
- package/dist/src/apollo/users.js +60 -0
- package/dist/src/components/account/profile.d.ts +8 -0
- package/dist/src/components/account/profile.js +137 -0
- package/dist/src/components/basics/copy-text-icon.d.ts +7 -0
- package/dist/src/components/basics/copy-text-icon.js +15 -0
- package/dist/src/components/basics/editable-string-list.d.ts +7 -0
- package/dist/src/components/basics/editable-string-list.js +41 -0
- package/dist/src/components/basics/json-display.d.ts +7 -0
- package/dist/src/components/basics/json-display.js +37 -0
- package/dist/src/components/basics/mui-auto-focus.d.ts +2 -0
- package/dist/src/components/basics/mui-auto-focus.js +16 -0
- package/dist/src/components/basics/text-area-field.d.ts +12 -0
- package/dist/src/components/basics/text-area-field.js +23 -0
- package/dist/src/components/basics/view-link-field.d.ts +8 -0
- package/dist/src/components/basics/view-link-field.js +6 -0
- package/dist/src/components/basics/view-markdown-field.d.ts +7 -0
- package/dist/src/components/basics/view-markdown-field.js +7 -0
- package/dist/src/components/basics/view-text-field.d.ts +7 -0
- package/dist/src/components/basics/view-text-field.js +6 -0
- package/dist/src/components/buttons/labeled-icon-button.d.ts +12 -0
- package/dist/src/components/buttons/labeled-icon-button.js +19 -0
- package/dist/src/components/css/loaders.d.ts +0 -0
- package/dist/src/components/css/loaders.js +1 -0
- package/dist/src/components/mailing-lists/sign-up.d.ts +5 -0
- package/dist/src/components/mailing-lists/sign-up.js +75 -0
- package/dist/src/components/notifications/action.d.ts +8 -0
- package/dist/src/components/notifications/action.js +15 -0
- package/dist/src/components/tech/load-techs.d.ts +7 -0
- package/dist/src/components/tech/load-techs.js +41 -0
- package/dist/src/components/tech/tech-autocomplete.d.ts +17 -0
- package/dist/src/components/tech/tech-autocomplete.js +15 -0
- package/dist/src/components/tips/load-tips.d.ts +7 -0
- package/dist/src/components/tips/load-tips.js +47 -0
- package/dist/src/components/tips/tip.d.ts +11 -0
- package/dist/src/components/tips/tip.js +44 -0
- package/dist/src/services/access/service.d.ts +26 -0
- package/dist/src/services/access/service.js +82 -0
- package/dist/src/services/locale/countries.d.ts +6 -0
- package/dist/src/services/locale/countries.js +481 -0
- package/dist/src/services/rest-api/request.d.ts +1 -0
- package/dist/src/services/rest-api/request.js +8 -0
- package/dist/src/services/rest-api/service.d.ts +21 -0
- package/dist/src/services/rest-api/service.js +79 -0
- package/dist/src/services/users/profile-service.d.ts +16 -0
- package/dist/src/services/users/profile-service.js +24 -0
- package/dist/src/services/users/user-preferences-service.d.ts +6 -0
- package/dist/src/services/users/user-preferences-service.js +41 -0
- package/dist/src/services/users/user-service.d.ts +22 -0
- package/dist/src/services/users/user-service.js +208 -0
- package/dist/src/services/utils/date.d.ts +1 -0
- package/dist/src/services/utils/date.js +4 -0
- package/dist/src/services/utils/functions.d.ts +1 -0
- package/dist/src/services/utils/functions.js +6 -0
- package/dist/src/services/utils/service.d.ts +3 -0
- package/dist/src/services/utils/service.js +9 -0
- package/dist/src/services/utils/string.d.ts +5 -0
- package/dist/src/services/utils/string.js +37 -0
- package/dist/src/services/utils/tree.d.ts +4 -0
- package/dist/src/services/utils/tree.js +65 -0
- package/dist/src/types/types.d.ts +3 -0
- package/dist/src/types/types.js +3 -0
- package/index.ts +36 -0
- package/package.json +32 -0
- package/src/apollo/access.ts +10 -0
- package/src/apollo/mailing-lists.ts +35 -0
- package/src/apollo/quotas.ts +22 -0
- package/src/apollo/techs.ts +16 -0
- package/src/apollo/tips.ts +48 -0
- package/src/apollo/user-preferences.ts +34 -0
- package/src/apollo/users.ts +66 -0
- package/src/components/account/profile.tsx +279 -0
- package/src/components/basics/copy-text-icon.tsx +34 -0
- package/src/components/basics/editable-string-list.tsx +97 -0
- package/src/components/basics/json-display.tsx +71 -0
- package/src/components/basics/mui-auto-focus.tsx +19 -0
- package/src/components/basics/text-area-field.tsx +63 -0
- package/src/components/basics/view-link-field.tsx +32 -0
- package/src/components/basics/view-markdown-field.tsx +31 -0
- package/src/components/basics/view-text-field.tsx +28 -0
- package/src/components/buttons/labeled-icon-button.tsx +53 -0
- package/src/components/css/loaders.tsx +0 -0
- package/src/components/mailing-lists/sign-up.tsx +126 -0
- package/src/components/notifications/action.tsx +50 -0
- package/src/components/tech/load-techs.tsx +66 -0
- package/src/components/tech/tech-autocomplete.tsx +65 -0
- package/src/components/tips/load-tips.tsx +75 -0
- package/src/components/tips/tip.tsx +96 -0
- package/src/services/access/service.ts +126 -0
- package/src/services/locale/countries.ts +483 -0
- package/src/services/rest-api/request.ts +10 -0
- package/src/services/rest-api/service.ts +130 -0
- package/src/services/users/profile-service.ts +28 -0
- package/src/services/users/user-preferences-service.ts +64 -0
- package/src/services/users/user-service.ts +310 -0
- package/src/services/utils/date.ts +6 -0
- package/src/services/utils/functions.ts +8 -0
- package/src/services/utils/service.ts +12 -0
- package/src/services/utils/string.ts +48 -0
- package/src/services/utils/tree.ts +88 -0
- package/src/types/types.ts +4 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Typography } from '@mui/material'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
label: string
|
|
6
|
+
value: string
|
|
7
|
+
style?: any
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default function ViewTextField({
|
|
11
|
+
label,
|
|
12
|
+
value,
|
|
13
|
+
style = {}
|
|
14
|
+
}: Props) {
|
|
15
|
+
|
|
16
|
+
// Render
|
|
17
|
+
return (
|
|
18
|
+
<div style={style}>
|
|
19
|
+
<Typography
|
|
20
|
+
variant='caption'>
|
|
21
|
+
{label}
|
|
22
|
+
</Typography>
|
|
23
|
+
<Typography variant='body1'>
|
|
24
|
+
{value}
|
|
25
|
+
</Typography>
|
|
26
|
+
</div>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Box, Button, ButtonProps, styled } from '@mui/material'
|
|
2
|
+
import { grey } from '@mui/material/colors'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
disabled?: boolean
|
|
6
|
+
icon: any
|
|
7
|
+
label: string | undefined
|
|
8
|
+
onClick: any
|
|
9
|
+
color?: string
|
|
10
|
+
textColor?: string
|
|
11
|
+
backgroundColor?: string
|
|
12
|
+
style?: any
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default function LabeledIconButton({
|
|
16
|
+
disabled,
|
|
17
|
+
icon,
|
|
18
|
+
label,
|
|
19
|
+
onClick,
|
|
20
|
+
color = grey[700],
|
|
21
|
+
textColor = grey[500],
|
|
22
|
+
backgroundColor = grey[100],
|
|
23
|
+
style = {}
|
|
24
|
+
}: Props) {
|
|
25
|
+
|
|
26
|
+
// Consts
|
|
27
|
+
const Icon = icon
|
|
28
|
+
|
|
29
|
+
const ColorButton = styled(Button)<ButtonProps>(({ theme }) => ({
|
|
30
|
+
color: color,
|
|
31
|
+
backgroundColor: 'transparent',
|
|
32
|
+
'&:hover': {
|
|
33
|
+
color: theme.palette.getContrastText(textColor),
|
|
34
|
+
backgroundColor: backgroundColor,
|
|
35
|
+
},
|
|
36
|
+
}))
|
|
37
|
+
|
|
38
|
+
// Render
|
|
39
|
+
// Wrap in a box, so that if there's no onClick event the button isn't
|
|
40
|
+
// clickable (pointerEvents set to none instead of auto).
|
|
41
|
+
return (
|
|
42
|
+
<Box sx={{ pointerEvents: onClick == null ? 'none' : 'auto' }}>
|
|
43
|
+
<ColorButton
|
|
44
|
+
disabled={disabled}
|
|
45
|
+
onClick={onClick}
|
|
46
|
+
variant='text'
|
|
47
|
+
startIcon={<Icon />}
|
|
48
|
+
style={style}>
|
|
49
|
+
{label}
|
|
50
|
+
</ColorButton>
|
|
51
|
+
</Box>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import { useMutation } from '@apollo/client/react'
|
|
3
|
+
import { mailingListSignupMutation } from '../../apollo/mailing-lists'
|
|
4
|
+
import { Alert, Button, TextField } from '@mui/material'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
mailingListName: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default function MailingListSignUp({
|
|
11
|
+
mailingListName
|
|
12
|
+
}: Props) {
|
|
13
|
+
|
|
14
|
+
// Types
|
|
15
|
+
type AlertSeverity = 'error' | 'warning' | 'info' | 'success' | undefined
|
|
16
|
+
|
|
17
|
+
// State
|
|
18
|
+
const [alertSeverity, setAlertSeverity] = useState<AlertSeverity>(undefined)
|
|
19
|
+
const [message, setMessage] = useState<string | undefined>(undefined)
|
|
20
|
+
|
|
21
|
+
const [email, setEmail] = useState('')
|
|
22
|
+
const [firstName, setFirstName] = useState('')
|
|
23
|
+
const [submitDisabled, setSubmitDisabled] = useState(false)
|
|
24
|
+
|
|
25
|
+
// GraphQL
|
|
26
|
+
const [fetchMailingListSignupMutation] =
|
|
27
|
+
useMutation<any>(mailingListSignupMutation, {
|
|
28
|
+
fetchPolicy: 'no-cache'
|
|
29
|
+
/* onCompleted: data => {
|
|
30
|
+
console.log('elementName: ' + elementName)
|
|
31
|
+
console.log(data)
|
|
32
|
+
},
|
|
33
|
+
onError: error => {
|
|
34
|
+
console.log(error)
|
|
35
|
+
} */
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
// Functions
|
|
39
|
+
function isEmail(search: string): boolean {
|
|
40
|
+
var serchFind: boolean
|
|
41
|
+
|
|
42
|
+
const regexp = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)
|
|
43
|
+
|
|
44
|
+
serchFind = regexp.test(search)
|
|
45
|
+
|
|
46
|
+
console.log(serchFind)
|
|
47
|
+
return serchFind
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function signUpForMailingList() {
|
|
51
|
+
|
|
52
|
+
// Verify email address
|
|
53
|
+
if (isEmail(email) === false) {
|
|
54
|
+
setAlertSeverity('error')
|
|
55
|
+
setMessage('The email address you entered is in valid')
|
|
56
|
+
} else {
|
|
57
|
+
setAlertSeverity(undefined)
|
|
58
|
+
setMessage(undefined)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Disable the submit button
|
|
62
|
+
setSubmitDisabled(true)
|
|
63
|
+
|
|
64
|
+
// Call the GraphQL mutation
|
|
65
|
+
var mailingListSignupData: any
|
|
66
|
+
|
|
67
|
+
await fetchMailingListSignupMutation({
|
|
68
|
+
variables: {
|
|
69
|
+
mailingListName: mailingListName,
|
|
70
|
+
email: email,
|
|
71
|
+
firstName: firstName
|
|
72
|
+
}
|
|
73
|
+
}).then(result => mailingListSignupData = result)
|
|
74
|
+
|
|
75
|
+
// Process the results
|
|
76
|
+
const results = mailingListSignupData.data.mailingListSignup
|
|
77
|
+
|
|
78
|
+
if (results.status === true) {
|
|
79
|
+
|
|
80
|
+
// Success
|
|
81
|
+
setAlertSeverity('success')
|
|
82
|
+
setMessage(`You've applied to enter in the private beta!`)
|
|
83
|
+
} else {
|
|
84
|
+
// Error
|
|
85
|
+
setAlertSeverity('error')
|
|
86
|
+
setMessage(results.message)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Render
|
|
91
|
+
return (
|
|
92
|
+
<>
|
|
93
|
+
<TextField
|
|
94
|
+
id='email'
|
|
95
|
+
label='Email address'
|
|
96
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
97
|
+
style={{ marginBottom: '1em', width: '100%' }}
|
|
98
|
+
value={email}
|
|
99
|
+
variant='outlined' />
|
|
100
|
+
|
|
101
|
+
<TextField
|
|
102
|
+
label='First name'
|
|
103
|
+
onChange={(e) => setFirstName(e.target.value)}
|
|
104
|
+
style={{ marginBottom: '1em', width: '100%' }}
|
|
105
|
+
value={firstName}
|
|
106
|
+
variant='outlined' />
|
|
107
|
+
|
|
108
|
+
<Button
|
|
109
|
+
// disabled={submitDisabled}
|
|
110
|
+
onClick={(e) => signUpForMailingList()}
|
|
111
|
+
style={{ marginBottom: '2em' }}
|
|
112
|
+
variant='contained'>
|
|
113
|
+
Sign-up
|
|
114
|
+
</Button>
|
|
115
|
+
|
|
116
|
+
{alertSeverity && message ?
|
|
117
|
+
<Alert
|
|
118
|
+
severity={alertSeverity}>
|
|
119
|
+
{message}
|
|
120
|
+
</Alert>
|
|
121
|
+
:
|
|
122
|
+
<></>
|
|
123
|
+
}
|
|
124
|
+
</>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import CloseIcon from '@mui/icons-material/Close'
|
|
2
|
+
import IconButton from '@mui/material/IconButton'
|
|
3
|
+
import Snackbar from '@mui/material/Snackbar'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
message: string
|
|
7
|
+
autoHideDuration: number
|
|
8
|
+
notificationOpened: boolean
|
|
9
|
+
setNotificationOpened: any
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function ActionNotification({
|
|
13
|
+
message,
|
|
14
|
+
autoHideDuration,
|
|
15
|
+
notificationOpened,
|
|
16
|
+
setNotificationOpened }: Props) {
|
|
17
|
+
|
|
18
|
+
const handleNotificationClose =
|
|
19
|
+
(event: React.SyntheticEvent | Event, reason?: string) => {
|
|
20
|
+
if (reason === 'clickaway') {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// setOpened(false)
|
|
25
|
+
setNotificationOpened(false)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const notificationAction = (
|
|
29
|
+
<>
|
|
30
|
+
<IconButton
|
|
31
|
+
size='small'
|
|
32
|
+
aria-label='close'
|
|
33
|
+
color='inherit'
|
|
34
|
+
onClick={handleNotificationClose}>
|
|
35
|
+
<CloseIcon fontSize='small' />
|
|
36
|
+
</IconButton>
|
|
37
|
+
</>
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
<Snackbar
|
|
43
|
+
open={notificationOpened}
|
|
44
|
+
autoHideDuration={autoHideDuration}
|
|
45
|
+
onClose={handleNotificationClose}
|
|
46
|
+
message={message}
|
|
47
|
+
action={notificationAction} />
|
|
48
|
+
</>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { useQuery } from '@apollo/client/react'
|
|
3
|
+
import { getTechsQuery } from '../../apollo/techs'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
userProfileId: string
|
|
7
|
+
resource: string,
|
|
8
|
+
setTechs: any
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function LoadTechByFilter({
|
|
12
|
+
userProfileId,
|
|
13
|
+
resource,
|
|
14
|
+
setTechs
|
|
15
|
+
}: Props) {
|
|
16
|
+
|
|
17
|
+
// GraphQL
|
|
18
|
+
const { refetch: fetchTechsQuery } =
|
|
19
|
+
useQuery<any>(getTechsQuery, {
|
|
20
|
+
fetchPolicy: 'no-cache'
|
|
21
|
+
/* onCompleted: data => {
|
|
22
|
+
console.log('elementName: ' + elementName)
|
|
23
|
+
console.log(data)
|
|
24
|
+
},
|
|
25
|
+
onError: error => {
|
|
26
|
+
console.log(error)
|
|
27
|
+
} */
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
// Functions
|
|
31
|
+
async function getTechsList() {
|
|
32
|
+
|
|
33
|
+
// Debug
|
|
34
|
+
const fnName = `getTechsList()`
|
|
35
|
+
|
|
36
|
+
// Query
|
|
37
|
+
const { data } = await
|
|
38
|
+
fetchTechsQuery({
|
|
39
|
+
userProfileId: userProfileId,
|
|
40
|
+
resource: resource
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// Set results
|
|
44
|
+
const results = data.getTechs
|
|
45
|
+
|
|
46
|
+
setTechs(results)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Effects
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
|
|
52
|
+
const fetchData = async () => {
|
|
53
|
+
await getTechsList()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Async call
|
|
57
|
+
const result = fetchData()
|
|
58
|
+
.catch(console.error)
|
|
59
|
+
|
|
60
|
+
}, [])
|
|
61
|
+
|
|
62
|
+
// Render
|
|
63
|
+
return (
|
|
64
|
+
<></>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import Autocomplete from '@mui/material/Autocomplete'
|
|
2
|
+
import FormControl from '@mui/material/FormControl'
|
|
3
|
+
import TextField, { TextFieldVariants } from '@mui/material/TextField'
|
|
4
|
+
|
|
5
|
+
interface Tech {
|
|
6
|
+
id: string
|
|
7
|
+
variantName: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
disabled?: boolean
|
|
12
|
+
label: string
|
|
13
|
+
onChange: any
|
|
14
|
+
setValue: any
|
|
15
|
+
style?: any
|
|
16
|
+
value: string | null // id
|
|
17
|
+
values: Tech[]
|
|
18
|
+
variant?: TextFieldVariants | undefined
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default function TechAutocomplete({
|
|
22
|
+
disabled = false,
|
|
23
|
+
label,
|
|
24
|
+
onChange = () => {},
|
|
25
|
+
setValue,
|
|
26
|
+
style = {},
|
|
27
|
+
value,
|
|
28
|
+
values,
|
|
29
|
+
variant = 'standard'
|
|
30
|
+
}: Props) {
|
|
31
|
+
|
|
32
|
+
const selectedTech = values.find((tech) => tech.id === value) || null
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<FormControl fullWidth>
|
|
36
|
+
<Autocomplete
|
|
37
|
+
disabled={disabled}
|
|
38
|
+
value={selectedTech}
|
|
39
|
+
onChange={(event, newValue) => {
|
|
40
|
+
|
|
41
|
+
// console.log(`newValue: ` + JSON.stringify(newValue))
|
|
42
|
+
|
|
43
|
+
const newId = newValue ? newValue.id : null
|
|
44
|
+
setValue(newId)
|
|
45
|
+
|
|
46
|
+
// Call the onChange function passed in, which must take a newId
|
|
47
|
+
// parameter of type string
|
|
48
|
+
onChange(newId)
|
|
49
|
+
}}
|
|
50
|
+
options={values}
|
|
51
|
+
getOptionLabel={(option) => option?.variantName ?? ''}
|
|
52
|
+
isOptionEqualToValue={(option, val) => option.id === val.id}
|
|
53
|
+
renderInput={(params) => (
|
|
54
|
+
<TextField
|
|
55
|
+
{...params}
|
|
56
|
+
label={label}
|
|
57
|
+
required
|
|
58
|
+
variant={variant}
|
|
59
|
+
/>
|
|
60
|
+
)}
|
|
61
|
+
style={style}
|
|
62
|
+
/>
|
|
63
|
+
</FormControl>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { useQuery } from '@apollo/client/react'
|
|
3
|
+
import { getTipsByUserProfileIdAndTagsQuery } from '../../apollo/tips'
|
|
4
|
+
|
|
5
|
+
// Component function interface
|
|
6
|
+
interface Props {
|
|
7
|
+
userProfileId: string
|
|
8
|
+
tipTags: string[]
|
|
9
|
+
setTips: any
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function LoadTips({
|
|
13
|
+
userProfileId,
|
|
14
|
+
tipTags,
|
|
15
|
+
setTips
|
|
16
|
+
}: Props) {
|
|
17
|
+
|
|
18
|
+
// GraphQL
|
|
19
|
+
const { refetch: fetchGetTipsByUserProfileIdAndTagsQuery } =
|
|
20
|
+
useQuery<any>(getTipsByUserProfileIdAndTagsQuery, {
|
|
21
|
+
fetchPolicy: 'no-cache'
|
|
22
|
+
/* onCompleted: data => {
|
|
23
|
+
console.log('attributeTypeName: ' + attributeTypeName)
|
|
24
|
+
console.log(data)
|
|
25
|
+
},
|
|
26
|
+
onError: error => {
|
|
27
|
+
console.log(error)
|
|
28
|
+
} */
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
// Functions
|
|
32
|
+
async function getTips() {
|
|
33
|
+
|
|
34
|
+
const fnName = `getTips()`
|
|
35
|
+
|
|
36
|
+
// Get tips data
|
|
37
|
+
const { data } = await
|
|
38
|
+
fetchGetTipsByUserProfileIdAndTagsQuery({
|
|
39
|
+
variables: {
|
|
40
|
+
userProfileId: userProfileId,
|
|
41
|
+
tags: tipTags
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// Set profile data
|
|
46
|
+
const results = data.getTipsByUserProfileIdAndTags
|
|
47
|
+
|
|
48
|
+
if (results != null) {
|
|
49
|
+
// console.log(`${fnName}: results: ${JSON.stringify(results)}`)
|
|
50
|
+
|
|
51
|
+
setTips(results.tips)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Effects
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
|
|
58
|
+
const fetchData = async () => {
|
|
59
|
+
await getTips()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Async call
|
|
63
|
+
if (userProfileId != null) {
|
|
64
|
+
const result = fetchData()
|
|
65
|
+
.catch(console.error)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
}, [userProfileId])
|
|
69
|
+
|
|
70
|
+
// Render
|
|
71
|
+
return (
|
|
72
|
+
<>
|
|
73
|
+
</>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { useMutation } from '@apollo/client/react'
|
|
2
|
+
import { upsertTipGotItMutation } from '../../apollo/tips'
|
|
3
|
+
import { Button, Card, CardActions, CardContent, Typography } from '@mui/material'
|
|
4
|
+
|
|
5
|
+
// Component function interface
|
|
6
|
+
interface Props {
|
|
7
|
+
name: string
|
|
8
|
+
label: string
|
|
9
|
+
text: string
|
|
10
|
+
setFocusRef: any
|
|
11
|
+
setTipVisible: any
|
|
12
|
+
style: any
|
|
13
|
+
userProfileId: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default function Tip({
|
|
17
|
+
name,
|
|
18
|
+
label,
|
|
19
|
+
text,
|
|
20
|
+
setFocusRef = undefined,
|
|
21
|
+
setTipVisible,
|
|
22
|
+
style = {},
|
|
23
|
+
userProfileId
|
|
24
|
+
}: Props) {
|
|
25
|
+
|
|
26
|
+
// GraphQL
|
|
27
|
+
const [sendUpsertTipGotItMutation] =
|
|
28
|
+
useMutation<any>(upsertTipGotItMutation, {
|
|
29
|
+
fetchPolicy: 'no-cache',
|
|
30
|
+
/* onCompleted: data => {
|
|
31
|
+
console.log('attributeTypeName: ' + attributeTypeName)
|
|
32
|
+
console.log(data)
|
|
33
|
+
},
|
|
34
|
+
onError: error => {
|
|
35
|
+
console.log(error)
|
|
36
|
+
} */
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// Functions
|
|
40
|
+
async function gotIt() {
|
|
41
|
+
|
|
42
|
+
const fetchData = async () => {
|
|
43
|
+
|
|
44
|
+
// Get tips data
|
|
45
|
+
const { data } = await
|
|
46
|
+
sendUpsertTipGotItMutation({
|
|
47
|
+
variables: {
|
|
48
|
+
name: name,
|
|
49
|
+
userProfileId: userProfileId
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// Set profile data
|
|
54
|
+
const results = data.upsertTipGotIt
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Async call
|
|
58
|
+
if (userProfileId != null) {
|
|
59
|
+
const result = fetchData()
|
|
60
|
+
.catch(console.error)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Render
|
|
65
|
+
return (
|
|
66
|
+
<div style={style}>
|
|
67
|
+
<Card style={{ background: '#6495ed', padding: '0.5em' }}>
|
|
68
|
+
<CardContent style={{ background: '#ffffff' }}>
|
|
69
|
+
<Typography
|
|
70
|
+
variant='caption'>
|
|
71
|
+
{label}
|
|
72
|
+
</Typography>
|
|
73
|
+
<Typography
|
|
74
|
+
variant='body1'>
|
|
75
|
+
{text}
|
|
76
|
+
</Typography>
|
|
77
|
+
</CardContent>
|
|
78
|
+
<CardActions style={{ background: '#ffffff' }}>
|
|
79
|
+
<div style={{ textAlign: 'right', width: '100%' }}>
|
|
80
|
+
<Button
|
|
81
|
+
onClick={(e) => {
|
|
82
|
+
setTipVisible(undefined)
|
|
83
|
+
gotIt()
|
|
84
|
+
|
|
85
|
+
if (setFocusRef != null) {
|
|
86
|
+
setFocusRef.current.focus()
|
|
87
|
+
}
|
|
88
|
+
}}>
|
|
89
|
+
Got it
|
|
90
|
+
</Button>
|
|
91
|
+
</div>
|
|
92
|
+
</CardActions>
|
|
93
|
+
</Card>
|
|
94
|
+
</div>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { getCookie, setCookie } from 'cookies-next'
|
|
2
|
+
import { isAdminUserQuery } from '../../apollo/access'
|
|
3
|
+
import { UsersService } from '../users/user-service'
|
|
4
|
+
|
|
5
|
+
interface ReqRes {
|
|
6
|
+
req: any
|
|
7
|
+
res: any
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class AccessService {
|
|
11
|
+
|
|
12
|
+
// Consts
|
|
13
|
+
clName = 'AccessService'
|
|
14
|
+
accessCodeCookieName = 'inventai-access-code'
|
|
15
|
+
|
|
16
|
+
// Services
|
|
17
|
+
usersService = new UsersService()
|
|
18
|
+
|
|
19
|
+
// Code
|
|
20
|
+
formatValidateAdminUser(json: any) {
|
|
21
|
+
|
|
22
|
+
if (json.isAdminUser == null) {
|
|
23
|
+
return { status: false,
|
|
24
|
+
message: 'Invalid reply' }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const record = json.isAdminUser
|
|
28
|
+
|
|
29
|
+
if (record.status == null) {
|
|
30
|
+
return { status: false,
|
|
31
|
+
message: 'Invalid reply' }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
var results =
|
|
35
|
+
{ status: record.status,
|
|
36
|
+
message: null }
|
|
37
|
+
|
|
38
|
+
if (record.message == null) {
|
|
39
|
+
results.message = record.message
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return results
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
validateAccessCode(
|
|
46
|
+
{ req, res }: ReqRes,
|
|
47
|
+
accessCode: string) {
|
|
48
|
+
|
|
49
|
+
// Fail if in production but ACCESS_CODE isn't defined
|
|
50
|
+
if (process.env.NODE_ENV === 'production' &&
|
|
51
|
+
!process.env.ACCESS_CODE) {
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check cookie for saved verification
|
|
56
|
+
const cookieAccessCode = getCookie(this.accessCodeCookieName, { req, res })
|
|
57
|
+
|
|
58
|
+
if (cookieAccessCode) {
|
|
59
|
+
if (cookieAccessCode === process.env.ACCESS_CODE) {
|
|
60
|
+
// Return validated successfully
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Check access in production
|
|
66
|
+
if (process.env.NODE_ENV === 'production' &&
|
|
67
|
+
process.env.ACCESS_CODE === accessCode) {
|
|
68
|
+
|
|
69
|
+
// Save admin access to a cookie
|
|
70
|
+
setCookie(
|
|
71
|
+
this.accessCodeCookieName,
|
|
72
|
+
accessCode,
|
|
73
|
+
{ req,
|
|
74
|
+
res,
|
|
75
|
+
maxAge: 60 * 60 * 24 * 30 }) // 30 days
|
|
76
|
+
|
|
77
|
+
// Return validated successfully
|
|
78
|
+
return true
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Otherwise fail for production, but pass for development
|
|
82
|
+
if (process.env.NODE_ENV === 'production') {
|
|
83
|
+
return false
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return true
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async validateUserIsAdmin(
|
|
90
|
+
{ req, res }: ReqRes,
|
|
91
|
+
apolloClient: any) {
|
|
92
|
+
|
|
93
|
+
// Debug
|
|
94
|
+
const fnName = `${this.clName}.validateUserIsAdmin`
|
|
95
|
+
|
|
96
|
+
// Get signed-in user id
|
|
97
|
+
const signedInId = await
|
|
98
|
+
this.usersService.getUserIdFromCookieAndVerify(
|
|
99
|
+
{ req, res },
|
|
100
|
+
apolloClient)
|
|
101
|
+
|
|
102
|
+
if (signedInId == null ||
|
|
103
|
+
signedInId === '') {
|
|
104
|
+
return {
|
|
105
|
+
status: false,
|
|
106
|
+
message: 'No signed-in user id given'
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// console.log(`${fnName}: signedInId: ${signedInId}`)
|
|
111
|
+
|
|
112
|
+
// Send a user is-admin query
|
|
113
|
+
var validateUserData: any
|
|
114
|
+
|
|
115
|
+
await apolloClient.query({
|
|
116
|
+
query: isAdminUserQuery,
|
|
117
|
+
variables: {
|
|
118
|
+
userProfileId: signedInId
|
|
119
|
+
}
|
|
120
|
+
}).then((result: any) => validateUserData = result)
|
|
121
|
+
|
|
122
|
+
// console.log(`validateUserIsAdmin(): ${JSON.stringify(validateUserData)}`)
|
|
123
|
+
|
|
124
|
+
return this.formatValidateAdminUser(validateUserData.data)
|
|
125
|
+
}
|
|
126
|
+
}
|