1
1
import type { ReactElement } from 'react' ;
2
- import React from 'react' ;
2
+ import React , { useEffect } from 'react' ;
3
3
import type { GetServerSideProps } from 'next' ;
4
4
import type { NextSeoProps } from 'next-seo' ;
5
5
import type { ClientError } from 'graphql-request' ;
@@ -48,6 +48,7 @@ import {
48
48
postAnalyticsQueryOptions ,
49
49
} from '@dailydotdev/shared/src/graphql/posts' ;
50
50
import type { PublicProfile } from '@dailydotdev/shared/src/lib/user' ;
51
+ import { canViewPostAnalytics } from '@dailydotdev/shared/src/lib/user' ;
51
52
import { ApiError , gqlClient } from '@dailydotdev/shared/src/graphql/common' ;
52
53
import { webappUrl } from '@dailydotdev/shared/src/lib/constants' ;
53
54
import { StaleTime } from '@dailydotdev/shared/src/lib/query' ;
@@ -64,6 +65,8 @@ import { TimeFormatType } from '@dailydotdev/shared/src/lib/dateFormat';
64
65
import { useQuery } from '@tanstack/react-query' ;
65
66
import dynamic from 'next/dynamic' ;
66
67
import { useRouter } from 'next/router' ;
68
+ import { useShowBoostButton } from '@dailydotdev/shared/src/features/boost/useShowBoostButton' ;
69
+ import { useAuthContext } from '@dailydotdev/shared/src/contexts/AuthContext' ;
67
70
import { getSeoDescription } from '../../../../components/PostSEOSchema' ;
68
71
import type { Props } from '../index' ;
69
72
import { seoTitle } from '../index' ;
@@ -101,7 +104,9 @@ export const getServerSideProps: GetServerSideProps<
101
104
const post = initialData . post as Post ;
102
105
const seo : NextSeoProps = {
103
106
canonical : post ?. slug ? `${ webappUrl } posts/${ post . slug } ` : undefined ,
104
- title : getTemplatedTitle ( seoTitle ( post ) ) ,
107
+ title : getTemplatedTitle (
108
+ [ seoTitle ( post ) , 'Analytics' ] . filter ( Boolean ) . join ( ' | ' ) ,
109
+ ) ,
105
110
description : getSeoDescription ( post ) ,
106
111
openGraph : {
107
112
images : [
@@ -162,6 +167,7 @@ const PostAnalyticsPage = ({
162
167
initialData,
163
168
} : PostAnalyticsPageProps ) : ReactElement => {
164
169
const router = useRouter ( ) ;
170
+ const { user, isAuthReady } = useAuthContext ( ) ;
165
171
166
172
const { post } = usePostById ( {
167
173
id,
@@ -171,9 +177,13 @@ const PostAnalyticsPage = ({
171
177
} ,
172
178
} ) ;
173
179
174
- const { data : postAnalytics } = useQuery (
175
- postAnalyticsQueryOptions ( { id : post ?. id } ) ,
176
- ) ;
180
+ const { data : postAnalytics } = useQuery ( {
181
+ ...postAnalyticsQueryOptions ( { id : post ?. id } ) ,
182
+ enabled : canViewPostAnalytics ( { post, user } ) ,
183
+ } ) ;
184
+
185
+ const canBoost = useShowBoostButton ( { post } ) ;
186
+ const isBoosting = ! ! post ?. flags ?. campaignId ;
177
187
178
188
const profileActivityList : AnalyticsNumberList = [
179
189
{
@@ -243,6 +253,28 @@ const PostAnalyticsPage = ({
243
253
} ,
244
254
] ;
245
255
256
+ const postLink = `${ webappUrl } posts/${
257
+ router ?. query ?. id === post . slug ? post . slug : post . id
258
+ } `;
259
+
260
+ useEffect ( ( ) => {
261
+ if ( ! isAuthReady ) {
262
+ return ;
263
+ }
264
+
265
+ if ( ! post ) {
266
+ return ;
267
+ }
268
+
269
+ if ( user ?. isTeamMember ) {
270
+ return ;
271
+ }
272
+
273
+ if ( ! canViewPostAnalytics ( { user, post } ) ) {
274
+ router . replace ( postLink ) ;
275
+ }
276
+ } , [ isAuthReady , post , postLink , router , user ] ) ;
277
+
246
278
return (
247
279
< div className = "mx-auto w-full max-w-[48rem]" >
248
280
< LayoutHeader
@@ -253,11 +285,7 @@ const PostAnalyticsPage = ({
253
285
size = { ButtonSize . Medium }
254
286
icon = { < ArrowIcon className = "-rotate-90" /> }
255
287
onClick = { ( ) => {
256
- router . push (
257
- `${ webappUrl } posts/${
258
- router ?. query ?. id === post . slug ? post . slug : post . id
259
- } `,
260
- ) ;
288
+ router . push ( postLink ) ;
261
289
} }
262
290
/>
263
291
< Typography
@@ -268,7 +296,14 @@ const PostAnalyticsPage = ({
268
296
>
269
297
Analytics
270
298
</ Typography >
271
- < BoostPostButton post = { post } buttonProps = { { size : ButtonSize . Small } } />
299
+ < BoostPostButton
300
+ post = { post }
301
+ buttonProps = { {
302
+ className : isBoosting && 'typo-footnote' ,
303
+ size : isBoosting ? ButtonSize . XSmall : ButtonSize . Small ,
304
+ } }
305
+ isActive = { isBoosting }
306
+ />
272
307
</ LayoutHeader >
273
308
< ResponsivePageContainer className = "!mx-0 !w-full !max-w-full gap-6" >
274
309
< SectionContainer >
@@ -317,36 +352,46 @@ const PostAnalyticsPage = ({
317
352
< div className = "size-2 rounded-full bg-brand-default" /> { ' ' }
318
353
< Typography type = { TypographyType . Footnote } > Organic</ Typography >
319
354
</ div >
320
- < div className = "flex items-center gap-1" >
321
- < div className = "size-2 rounded-full bg-accent-blueCheese-default" /> { ' ' }
322
- < Typography type = { TypographyType . Footnote } > Boosted</ Typography >
323
- </ div >
355
+ { /* TODO post-analytics enable boosting data */ }
356
+ { false && (
357
+ < div className = "flex items-center gap-1" >
358
+ < div className = "size-2 rounded-full bg-accent-blueCheese-default" /> { ' ' }
359
+ < Typography type = { TypographyType . Footnote } >
360
+ Boosted
361
+ </ Typography >
362
+ </ div >
363
+ ) }
324
364
</ div >
325
365
</ div >
326
366
< ImpressionsChart post = { post } />
327
367
</ SectionContainer >
328
368
< Divider className = { dividerClassName } />
329
- < SectionContainer >
330
- < SectionHeader > Boost your post</ SectionHeader >
331
- < Typography
332
- type = { TypographyType . Callout }
333
- color = { TypographyColor . Tertiary }
334
- >
335
- Give your content the spotlight it deserves. Our auto-targeting
336
- engine gets your post in front of developers most likely to care.
337
- </ Typography >
338
- < Typography
339
- type = { TypographyType . Footnote }
340
- color = { TypographyColor . Boost }
341
- >
342
- Reach up to 100k more developers now
343
- </ Typography >
344
- < BoostPostButton
345
- post = { post }
346
- buttonProps = { { size : ButtonSize . Small , className : 'mr-auto' } }
347
- />
348
- </ SectionContainer >
349
- < Divider className = { dividerClassName } />
369
+ { canBoost && (
370
+ < >
371
+ < SectionContainer >
372
+ < SectionHeader > Boost your post</ SectionHeader >
373
+ < Typography
374
+ type = { TypographyType . Callout }
375
+ color = { TypographyColor . Tertiary }
376
+ >
377
+ Give your content the spotlight it deserves. Our auto-targeting
378
+ engine gets your post in front of developers most likely to
379
+ care.
380
+ </ Typography >
381
+ < Typography
382
+ type = { TypographyType . Footnote }
383
+ color = { TypographyColor . Boost }
384
+ >
385
+ Reach up to 100k more developers now
386
+ </ Typography >
387
+ < BoostPostButton
388
+ post = { post }
389
+ buttonProps = { { size : ButtonSize . Small , className : 'mr-auto' } }
390
+ />
391
+ </ SectionContainer >
392
+ < Divider className = { dividerClassName } />
393
+ </ >
394
+ ) }
350
395
{ /* TODO post-analytics enable boosting data */ }
351
396
{ false && (
352
397
< SectionContainer >
0 commit comments