diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 370eeac58..f9de74c71 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -6,6 +6,7 @@ updates:
reviewers:
- 'oap75'
- 'olehmell'
+ - "iv1310"
schedule:
interval: 'weekly'
commit-message:
diff --git a/README.md b/README.md
index 5013ea38b..73efdac9b 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,61 @@ PolkaVerse is a niche social site built on the Subsocial network. It focuses on
Visit Subsocial's [website](https://subsocial.network) to learn more about the project.
+## Guide to build and deploy polkaverse
+
+### Build the docker images
+1. Prepare the [dockerfile](./docker/Dockerfile) and adjust the config if needed.
+2. Build the image in local with this command and please ensure to add build argument.
+```bash
+$ docker build --build-arg GH_GA_ID=valueREDACTED --build-arg GH_APP_KIND=valueREDACTED --build-arg GH_HCAPTCHA_SITE_KEY=valueREDACTED --build-arg GH_AMP_ID=valueREDACTED --build-arg GH_OFFCHAIN_SIGNER_URL=valueREDACTED --build-arg GH_CONNECTION_KIND=valueREDACTED --build-arg GH_SELLER_CLIENT_ID=valueREDACTED --build-arg GH_SERVER_MNEMONIC==valueREDACTED --build-arg GH_SELLER_TOKEN_SIGNER=valueREDACTED --build-arg GH_NEXT_PUBLIC_DATAHUB_QUERY_URL=valueREDACTED --build-arg GH_NEXT_PUBLIC_DATAHUB_SUBSCRIPTION_URL=valueREDACTED --build-arg GH_DATAHUB_QUEUE_URL=valueREDACTED --build-arg GH_DATAHUB_QUEUE_TOKEN=valueREDACTED -t polkaverse-docker-image:latest .
+```
+Notes:
+Please execute the build process with theses build arguments, you need to specify the value.
+* GH_GA_ID=valueREDACTED
+* GH_APP_KIND=valueREDACTED
+* GH_HCAPTCHA_SITE_KEY=valueREDACTED
+* GH_AMP_ID=valueREDACTED
+* GH_OFFCHAIN_SIGNER_URL=valueREDACTED
+* GH_CONNECTION_KIND=valueREDACTED
+* GH_SELLER_CLIENT_ID=valueREDACTED
+* GH_SELLER_TOKEN_SIGNER=valueREDACTED
+* GH_SERVER_MNEMONIC=valueREDACTED
+* GH_NEXT_PUBLIC_DATAHUB_QUERY_URL=valueREDACTED
+* GH_NEXT_PUBLIC_DATAHUB_SUBSCRIPTION_URL=valueREDACTED
+* GH_DATAHUB_QUEUE_URL=valueREDACTED
+* GH_DATAHUB_QUEUE_TOKEN=valueREDACTED
+3. Then check the docker images that has been builded.
+```bash
+$ docker images | grep "polkaverse"
+```
+
+### Run the container with docker-compose
+1. To run the docker images with docker-compose, please prepare the docker-compose.yaml config file at first.
+```yaml
+# docker-compose.yml
+version: "3"
+services:
+ web-ui:
+ image: polkaverse-docker-image:latest
+ ports:
+ - "3003:3003" # Application port
+ container_name: polkaverse-web-app
+ restart: on-failure
+```
+```bash
+$ docker-compose -f docker-compose.yaml up -d
+```
+2. Check the running container with this command.
+```bash
+$ docker-compose ps
+$ docker-compose logs
+```
+3. Test to connect to the application.
+```bash
+$ curl -I http://localhost:3003
+```
+
+
## Run locally
Clone this repo:
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index 9bccc0272..1efa720e6 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -9,10 +9,3 @@ services:
container_name: subsocial-web-ui
restart: on-failure
network_mode: "host"
-
- nginx:
- build: ./nginx
- container_name: subsocial-proxy
- image: dappforce/subsocial-proxy:latest
- restart: on-failure
- network_mode: "host"
diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile
deleted file mode 100644
index 954ed60ea..000000000
--- a/docker/nginx/Dockerfile
+++ /dev/null
@@ -1,9 +0,0 @@
-FROM nginx:alpine
-
-RUN rm /etc/nginx/conf.d/*
-
-COPY ./default.conf /etc/nginx/conf.d/
-
-EXPOSE 80
-
-CMD [ "nginx", "-g", "daemon off;" ]
\ No newline at end of file
diff --git a/docker/nginx/default.conf b/docker/nginx/default.conf
deleted file mode 100644
index 0eaee85be..000000000
--- a/docker/nginx/default.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-server {
- listen 80 default_server;
-
- server_name _;
-
- server_tokens off;
-
- location / {
- proxy_pass http://localhost:3003;
- }
-
- location /bc/ {
- rewrite ^/bc(.*) /$1 break;
- proxy_pass http://localhost:3002;
- }
-}
diff --git a/src/components/activity/MyNotifications.tsx b/src/components/activity/MyNotifications.tsx
index e62c96124..92b45c589 100644
--- a/src/components/activity/MyNotifications.tsx
+++ b/src/components/activity/MyNotifications.tsx
@@ -10,13 +10,13 @@ const NOTIFICATION_TITLE = 'My notifications'
export const MyNotifications = () => {
const myAddress = useMyAddress()
- const isInitializedProxy = useMyAccount(state => state.isInitializedProxy)
+ const isInitialized = useMyAccount(state => state.isInitialized)
if (!myAddress) return
return (
- {!isInitializedProxy ? (
+ {!isInitialized ? (
) : (
diff --git a/src/components/activity/NotifCounter.tsx b/src/components/activity/NotifCounter.tsx
index d428b0101..af9227f7c 100644
--- a/src/components/activity/NotifCounter.tsx
+++ b/src/components/activity/NotifCounter.tsx
@@ -34,7 +34,7 @@ function InnerNotifCounterProvider(props: React.PropsWithChildren<{}>) {
storageKeyType: 'user',
})
const myAddress = useMyAddress()
- const isInitializedProxy = useMyAccount(state => state.isInitializedProxy)
+ const isInitialized = useMyAccount(state => state.isInitialized)
const [unreadCount, setUnreadCount] = useState(0)
const [previousLastRead, setPreviousLastRead] = useState(null)
@@ -47,7 +47,7 @@ function InnerNotifCounterProvider(props: React.PropsWithChildren<{}>) {
}
useEffect(() => {
- if (!isInitializedProxy || !myAddress) return
+ if (!isInitialized || !myAddress) return
;(async () => {
const unreadCount = await getNotificationsCount({
address: myAddress,
@@ -55,7 +55,7 @@ function InnerNotifCounterProvider(props: React.PropsWithChildren<{}>) {
})
setUnreadCount(unreadCount)
})()
- }, [myAddress, isInitializedProxy])
+ }, [myAddress, isInitialized])
return (
(
export const NotificationsBell = ({ unreadCount }: NotificationsProps) => {
const myAddress = useMyAddress()
- const isInitializedProxy = useMyAccount(state => state.isInitializedProxy)
+ const isInitialized = useMyAccount(state => state.isInitialized)
const { getLastReadNotif } = useNotifCounterContext()
if (!enableNotifications) return null
- if (!unreadCount || unreadCount <= 0 || !isInitializedProxy)
- return
+ if (!unreadCount || unreadCount <= 0 || !isInitialized) return
const showWithoutCount = !getLastReadNotif(myAddress)
diff --git a/src/components/auth/MyAccountsContext.tsx b/src/components/auth/MyAccountsContext.tsx
index e41e01622..617032223 100644
--- a/src/components/auth/MyAccountsContext.tsx
+++ b/src/components/auth/MyAccountsContext.tsx
@@ -29,13 +29,14 @@ import { fetchChainsInfo } from 'src/rtk/features/chainsInfo/chainsInfoSlice'
import { fetchProfileSpace } from 'src/rtk/features/profiles/profilesSlice'
import { fetchEntityOfSpaceIdsByFollower } from 'src/rtk/features/spaceIds/followedSpaceIdsSlice'
import { useMyAccount } from 'src/stores/my-account'
-import { AnyAccountId, EmailAccount } from 'src/types'
+import { AnyAccountId, DataSourceTypes, EmailAccount } from 'src/types'
import useSubsocialEffect from '../api/useSubsocialEffect'
import { useAccountSelector } from '../profile-selector/AccountSelector'
import { useIsMobileWidthOrDevice } from '../responsive'
import { reloadSpaceIdsFollowedByAccount } from '../spaces/helpers/reloadSpaceIdsFollowedByAccount'
import { equalAddresses } from '../substrate'
import { getSignerToken, isProxyAdded } from '../utils/OffchainSigner/ExternalStorage'
+import { getSubsocialApi } from '../utils/SubsocialConnect'
import { desktopWalletConnect, mobileWalletConection } from './utils'
//
// Types
@@ -101,6 +102,7 @@ export function MyAccountsProvider(props: React.PropsWithChildren<{}>) {
const reloadAccountIdsByFollower = useCreateReloadAccountIdsByFollower()
const reloadSpaceIdsRelatedToAccount = useCreateReloadSpaceIdsRelatedToAccount()
const address = useMyAddress()
+ const isInitialized = useMyAccount(state => state.isInitialized)
const { getAllEmailAccounts } = useEmailAccount()
const [, recheck] = useReducer(x => (x + 1) % 16384, 0)
const isMobile = useIsMobileWidthOrDevice()
@@ -132,7 +134,7 @@ export function MyAccountsProvider(props: React.PropsWithChildren<{}>) {
}, [status])
useSubsocialEffect(
- ({ substrate, subsocial }) => {
+ ({ substrate }) => {
if (!address) return
let unsubAccountInfo: UnsubscribeFn
@@ -141,13 +143,10 @@ export function MyAccountsProvider(props: React.PropsWithChildren<{}>) {
const readyApi = await substrate.api
Promise.all([
- reloadSpaceIdsFollowedByAccount({ substrate, dispatch: dispatch, account: address }),
+ reloadSpaceIdsFollowedByAccount({ substrate, dispatch, account: address }),
reloadAccountIdsByFollower(address),
reloadSpaceIdsRelatedToAccount(address),
- dispatch(fetchProfileSpace({ id: address, api: subsocial })),
- dispatch(fetchEntityOfSpaceIdsByFollower({ id: address, reload: true, api: subsocial })),
dispatch(fetchChainsInfo({})),
- dispatch(fetchAddressLikeCounts({ address, postIds: null })),
])
unsubAccountInfo = await readyApi.query.system.account(
@@ -166,6 +165,20 @@ export function MyAccountsProvider(props: React.PropsWithChildren<{}>) {
},
[address],
)
+ useEffect(() => {
+ if (!isInitialized || !address) return
+ dispatch(
+ fetchEntityOfSpaceIdsByFollower({
+ id: address,
+ dataSource: DataSourceTypes.SQUID,
+ api: getSubsocialApi(),
+ }),
+ )
+ dispatch(
+ fetchProfileSpace({ id: address, api: getSubsocialApi(), dataSource: DataSourceTypes.SQUID }),
+ )
+ dispatch(fetchAddressLikeCounts({ address, postIds: null }))
+ }, [address, isInitialized])
const state = useMemo(
() => ({ accounts, status, emailAccounts }),
diff --git a/src/components/main/HomePage.tsx b/src/components/main/HomePage.tsx
index 6e04e7fd3..ccf0ce860 100644
--- a/src/components/main/HomePage.tsx
+++ b/src/components/main/HomePage.tsx
@@ -7,7 +7,10 @@ import { useCallback, useEffect, useState } from 'react'
import config from 'src/config'
import { useSendEvent } from 'src/providers/AnalyticContext'
import { getInitialPropsWithRedux } from 'src/rtk/app'
+import { useAppSelector } from 'src/rtk/app/store'
import { useFetchTotalStake } from 'src/rtk/features/creators/totalStakeHooks'
+import { selectSpaceIdsByFollower } from 'src/rtk/features/spaceIds/followedSpaceIdsSlice'
+import { useMyAccount } from 'src/stores/my-account'
import { PostKind } from 'src/types/graphql-global-types'
import { getAmountRange } from 'src/utils/analytics'
import { useIsSignedIn, useMyAddress } from '../auth/MyAccountsContext'
@@ -147,9 +150,20 @@ const TabsHomePage = ({
setFiltersInUrl(router, key, filterType, { ref: refId })
}
+ const isInitialized = useMyAccount(state => state.isInitialized)
+ const followedIds = useAppSelector(state => {
+ return selectSpaceIdsByFollower(state, myAddress)
+ })
+
+ const isLoadingFollowedIds = followedIds === undefined
useEffect(() => {
- onChangeKey(tab)
- }, [isSignedIn])
+ if (!isInitialized || !isSignedIn || isLoadingFollowedIds) return
+ if (followedIds.length === 0) {
+ setFiltersInUrl(router, 'posts', { type: 'hot' }, { ref: refId })
+ } else {
+ onChangeKey(tab)
+ }
+ }, [followedIds, isInitialized])
const handleScroll = () => {
const currentScrollPos = window.pageYOffset
diff --git a/src/components/posts/editor/FullEditor.tsx b/src/components/posts/editor/FullEditor.tsx
index c55a5b8e7..42ce7529e 100644
--- a/src/components/posts/editor/FullEditor.tsx
+++ b/src/components/posts/editor/FullEditor.tsx
@@ -195,7 +195,10 @@ const FullEditor = ({
{!totalStake?.hasStakedEnough && (
diff --git a/src/components/posts/editor/ModalEditor.tsx b/src/components/posts/editor/ModalEditor.tsx
index c72e05ad8..c9343b36a 100644
--- a/src/components/posts/editor/ModalEditor.tsx
+++ b/src/components/posts/editor/ModalEditor.tsx
@@ -105,7 +105,7 @@ export const PostEditorModalBody = ({
const [spaceId, setSpaceId] = useState(defaultSpace)
const { loading } = useFetchSpaces({ ids: spaceIds, dataSource: DataSourceTypes.SQUID })
- const { saveContent } = useAutoSaveFromForm({ entity: 'post' })
+ const { savedData, saveContent } = useAutoSaveFromForm({ entity: 'post' })
useEffect(() => {
setSpaceId(defaultSpace)
@@ -201,7 +201,7 @@ export const PostEditorModalBody = ({
)
return (
-
{/* value and onChange are provided by Form.Item */}
diff --git a/src/components/posts/editor/index.module.sass b/src/components/posts/editor/index.module.sass
index 0953206d3..feb1dbef5 100644
--- a/src/components/posts/editor/index.module.sass
+++ b/src/components/posts/editor/index.module.sass
@@ -35,6 +35,9 @@
\:global .ant-tabs-nav
margin: 0
+.EditorBodyContentContainer
+ width: $max_width_content
+
.AdvancedBody
width: 325px
diff --git a/src/components/posts/pinned-post.ts b/src/components/posts/pinned-post.ts
index 230686cd9..ddafadef1 100644
--- a/src/components/posts/pinned-post.ts
+++ b/src/components/posts/pinned-post.ts
@@ -1,7 +1,7 @@
import { getLastestPostIdsInSpace } from 'src/graphql/apis'
import { GqlClient } from 'src/graphql/ApolloProvider'
-const PINNED_POST_IDS: string[] = ['91982']
+const PINNED_POST_IDS: string[] = ['100229']
export const PINNED_POST_ID = PINNED_POST_IDS[Math.floor(Math.random() * PINNED_POST_IDS.length)]
const COMMUNITY_SPACE_ID = '1244'
diff --git a/src/stores/my-account.ts b/src/stores/my-account.ts
index d50f218b1..aa073fef9 100644
--- a/src/stores/my-account.ts
+++ b/src/stores/my-account.ts
@@ -16,7 +16,14 @@ import { useAnalytics } from './analytics'
import { create } from './utils'
type State = {
+ /**
+ * `isInitialized` is `true` when the addresses (address & parentProxyAddress) are all set
+ * but there is still a case where the proxy is invalid and user will be logged out after that
+ */
isInitialized?: boolean
+ /**
+ * `isInitializedProxy` is `true` when the initialization process is all done, including checking the proxy
+ */
isInitializedProxy?: boolean
preferredWallet: any | null
@@ -148,13 +155,14 @@ export const useMyAccount = create()((set, get) => ({
accountStorage.remove()
accountAddressStorage.remove()
set({ address: null })
+ } else {
+ accountAddressStorage.set(address)
}
}
- set({ isInitialized: true })
+ set({ isInitialized: true, parentProxyAddress: parentProxyAddress || undefined })
if (parentProxyAddress) {
- set({ parentProxyAddress })
try {
const proxies = await getProxies(parentProxyAddress)
const currentProxy = proxies.find(({ address }) => address === get().address)