Skip to content

Commit

Permalink
Merge pull request #136 from dappforce/deploy/grill-integration
Browse files Browse the repository at this point in the history
Grill Comment Integration
  • Loading branch information
olehmell authored Sep 11, 2023
2 parents 0c5ed9a + d3bf915 commit e8854f4
Show file tree
Hide file tree
Showing 38 changed files with 819 additions and 202 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/build-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ on:
- staging
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
front_build:
Expand Down Expand Up @@ -72,6 +72,7 @@ jobs:
GH_GA_ID=UA-204866512-2
GH_APP_KIND=polkaverse
GH_HCAPTCHA_SITE_KEY=${{ secrets.PROD_HCAPTCHA_SITE_KEY }}
GH_AMP_ID=2eeca0e8a0163c89e3f023c971e426a6
GH_OFFCHAIN_SIGNER_URL=https://signer.subsocial.network
GH_CONNECTION_KIND=main
Expand Down Expand Up @@ -156,7 +157,6 @@ jobs:
- name: Recreate HPA
run: kubectl create -f $GITHUB_WORKSPACE/deployment/hpa/hpa.yaml


front-bk-prod-deploy:
name: bk-prod-deploy
needs: front_build
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/feature-based.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ on:
branches:
- deploy/**
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
front_build:
Expand All @@ -28,7 +28,7 @@ jobs:
- name: Set up Docker context for buildx
id: buildx-context
run: |
docker context create builders
docker context create builders
- name: Set up Docker Buildx
id: buildx
Expand Down Expand Up @@ -62,6 +62,7 @@ jobs:
GH_GA_ID=fake
GH_APP_KIND=polkaverse
GH_HCAPTCHA_SITE_KEY=3beeddac-2dce-41cc-8e18-338118426c38
GH_AMP_ID=71bf5a46800fedba5e9a01243b988164
GH_OFFCHAIN_SIGNER_URL=https://signer.subsocial.network
GH_CONNECTION_KIND=dev
tags: |
Expand Down
1 change: 1 addition & 0 deletions ci.env
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ APP_KIND='$GH_APP_KIND'
APP_BASE_URL='$GH_APP_BASE_URL'
HCAPTCHA_SITE_KEY='$GH_HCAPTCHA_SITE_KEY'
OFFCHAIN_SIGNER_URL='$GH_OFFCHAIN_SIGNER_URL'
AMP_ID='$GH_AMP_ID'
5 changes: 4 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ARG GH_CONNECTION_KIND
ARG GH_APP_KIND
ARG GH_APP_BASE_URL
ARG GH_HCAPTCHA_SITE_KEY
ARG GH_AMP_ID
ARG GH_OFFCHAIN_SIGNER_URL

ENV SUBSTRATE_URL=${GH_SUBSTRATE_URL} \
Expand All @@ -21,6 +22,7 @@ ENV SUBSTRATE_URL=${GH_SUBSTRATE_URL} \
APP_KIND=${GH_APP_KIND} \
APP_BASE_URL=${GH_APP_BASE_URL} \
HCAPTCHA_SITE_KEY=${GH_HCAPTCHA_SITE_KEY} \
AMP_ID=${GH_AMP_ID} \
OFFCHAIN_SIGNER_URL=${GH_OFFCHAIN_SIGNER_URL} \
CONNECTION_KIND=${GH_CONNECTION_KIND}

Expand Down Expand Up @@ -50,6 +52,7 @@ ARG GH_CONNECTION_KIND
ARG GH_APP_KIND
ARG GH_APP_BASE_URL
ARG GH_HCAPTCHA_SITE_KEY
ARG GH_AMP_ID
ARG GH_OFFCHAIN_SIGNER_URL

ENV SUBSTRATE_URL=${GH_SUBSTRATE_URL} \
Expand All @@ -60,7 +63,7 @@ ENV SUBSTRATE_URL=${GH_SUBSTRATE_URL} \
GA_ID=${GH_GA_ID} \
APP_KIND=${GH_APP_KIND} \
APP_BASE_URL=${GH_APP_BASE_URL} \
HCAPTCHA_SITE_KEY=${GH_HCAPTCHA_SITE_KEY} \
AMP_ID=${GH_AMP_ID} \
OFFCHAIN_SIGNER_URL=${GH_OFFCHAIN_SIGNER_URL} \
CONNECTION_KIND=${GH_CONNECTION_KIND}

Expand Down
1 change: 1 addition & 0 deletions export-env.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const varsToExport = [
'MAINTENANCE_TEXT',

'GA_ID',
'AMP_ID',

'HCAPTCHA_SITE_KEY',

Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"cypress": "^10.11.0",
"cypress-network-idle": "^1.10.2",
"cypress-wait-until": "^1.7.2",
"eslint": "^8.28.0",
"eslint": "^8.46.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-prefer-object-spread": "^1.2.1",
Expand All @@ -81,6 +81,7 @@
"typescript": "^4.8.4"
},
"dependencies": {
"@amplitude/analytics-browser": "^2.2.3",
"@ant-design/icons": "^4.2.1",
"@antv/g2plot": "^2.3.10",
"@apollo/client": "^3.7.10",
Expand All @@ -93,6 +94,8 @@
"@subsocial/api": "0.8.10",
"@subsocial/definitions": "0.8.10",
"@subsocial/elasticsearch": "0.8.10",
"@subsocial/grill-widget": "^0.0.12",
"@subsocial/resource-discussions": "^0.0.3",
"@subsocial/utils": "0.8.10",
"@tiptap/extension-highlight": "^2.0.0-beta.33",
"@tiptap/extension-image": "^2.0.0-beta.27",
Expand Down
3 changes: 3 additions & 0 deletions public/images/grillchat.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
112 changes: 112 additions & 0 deletions src/components/chat/ChatFloatingModal.module.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
@import 'src/styles/subsocial-vars.scss'

.ChatFloatingWrapper
z-index: 10
position: fixed
bottom: $space_normal
right: $space_normal

.ChatUnreadCount
position: absolute
padding: 2px $space_tiny
top: 0
right: 0
font-size: $font_tiny
background: red
border-radius: 32px
transform: translate(25%, -25%)
color: white

.ChatFloatingButton
padding: $space_small $space_normal
// To offset optical illusion from the grill icon
padding-left: $space_small
border-radius: 32px
font-size: 1rem
color: white !important
display: flex
justify-content: center
height: auto
align-items: center
background: linear-gradient(95.39deg, #C43333 9.79%, #F9A11E 135.53%) !important
gap: $space_tiny
border: none

&:hover, &:focus
filter: brightness(1.1)

img
display: block
height: 1.1rem

.ChatContainer
z-index: 1010
position: fixed
bottom: 0
left: 0
width: 100%
height: 100vh
display: flex
flex-direction: column
justify-content: flex-end

.ChatOverlay
position: absolute
inset: 0
width: 100%
height: 100%
background-color: rgba(0, 0, 0, .2)
transition: opacity 0.2s ease-out
opacity: 1

.ChatContent
height: 90vh
height: 90dvh
width: 100%
background: #F8FAFC
border-radius: $border_radius_huge
opacity: 1
transform: translateY(0)
transition: transform 0.3s ease-in-out, opacity 0.2s ease-in-out
display: flex
flex-direction: column

.ChatControl
display: flex
align-items: center
justify-content: center
padding-top: $space-tiny

button
border-radius: 50%
background: #F0F1F9
border: none
display: flex
align-items: center
justify-content: center
width: 2rem
height: 2rem
padding: 0
font-size: 1rem

.ChatIframe
flex: 1

iframe
display: block
border-radius: $border_radius_large
width: 100%
height: 100%
border: none

&.ChatContainerHidden
pointer-events: none

.ChatOverlay
opacity: 0

.ChatContent
transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out
opacity: 0
transform: translateY(100%)

101 changes: 101 additions & 0 deletions src/components/chat/ChatFloatingModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { Button } from 'antd'
import clsx from 'clsx'
import { useEffect, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
import { HiChevronDown } from 'react-icons/hi2'
import { useSendEvent } from 'src/providers/AnalyticContext'
import { useChatOpenState } from 'src/rtk/app/hooks'
import { useAppSelector } from 'src/rtk/app/store'
import { ChatEntity } from 'src/rtk/features/chat/chatSlice'
import { disablePageScroll, enablePageScroll } from 'src/utils/window'
import { useResponsiveSize } from '../responsive'
import styles from './ChatFloatingModal.module.sass'
import ChatIframe from './ChatIframe'

export default function ChatFloatingModal() {
const { isLargeDesktop } = useResponsiveSize()
const sendEvent = useSendEvent()
const [isOpen, setIsOpen] = useChatOpenState()
const entity = useAppSelector(state => state.chat.entity)

const [unreadCount, setUnreadCount] = useState(0)

useEffect(() => {
if (!entity) return

const unreadCountFromStorage = getUnreadCount(entity)
if (unreadCountFromStorage && !isNaN(unreadCountFromStorage)) {
setUnreadCount(unreadCountFromStorage)
}
}, [entity])

const hasOpened = useRef(false)
const toggleChat = () => {
let event
if (isOpen) {
event = 'close_grill_iframe'
} else {
event = 'open_grill_iframe'
setUnreadCount(0)
if (entity) saveUnreadCount(entity, 0)
}
sendEvent(event)

if (!isOpen) disablePageScroll()
else enablePageScroll()

setIsOpen(!isOpen)
hasOpened.current = true
}

if (isLargeDesktop) {
return null
}

const onUnreadCountChange = (count: number) => {
if (count > 0 && entity) {
setUnreadCount(count)
saveUnreadCount(entity, count)
}
}

if (!entity) return null

return (
<>
{createPortal(
<div className={clsx(styles.ChatContainer, !isOpen && styles.ChatContainerHidden)}>
<div className={clsx(styles.ChatOverlay)} onClick={() => setIsOpen(false)} />
<div className={clsx(styles.ChatContent)}>
<div className={clsx(styles.ChatControl)}>
<Button onClick={toggleChat}>
<HiChevronDown />
</Button>
</div>
<ChatIframe onUnreadCountChange={onUnreadCountChange} className={styles.ChatIframe} />
</div>
</div>,
document.body,
)}
{createPortal(
<div className={styles.ChatFloatingWrapper}>
<Button className={styles.ChatFloatingButton} onClick={toggleChat}>
<img src='/images/grillchat.svg' alt='GrillChat' />
<span>Comments</span>
</Button>
{!!unreadCount && <span className={styles.ChatUnreadCount}>{unreadCount}</span>}
</div>,
document.body,
)}
</>
)
}

type Entity = NonNullable<ChatEntity['entity']>
function getUnreadCount(entity: Entity) {
return parseInt(localStorage.getItem(`unreadCount:${entity.type}:${entity.data.id}`) ?? '') ?? 0
}

function saveUnreadCount(entity: Entity, count: number) {
localStorage.setItem(`unreadCount:${entity.type}:${entity.data.id}`, count.toString() ?? '0')
}
Loading

0 comments on commit e8854f4

Please sign in to comment.