Skip to content

Commit

Permalink
Merge pull request #709 from systemli/Add-Fields-for-Instagram-and-Th…
Browse files Browse the repository at this point in the history
…reads

💄 Add Fields for Instagram and Threads
  • Loading branch information
0x46616c6b authored Feb 1, 2025
2 parents 1e1228d + 9a9822e commit 6514474
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/api/Ticker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export interface TickerInformation {
email: string
twitter: string
facebook: string
threads: string
instagram: string
telegram: string
mastodon: string
bluesky: string
Expand Down
42 changes: 42 additions & 0 deletions src/components/ticker/form/Instagram.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { faInstagram } from '@fortawesome/free-brands-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { InputAdornment, TextField } from '@mui/material'
import { FC } from 'react'
import { Controller, useFormContext } from 'react-hook-form'

const Instagram: FC = () => {
const { control } = useFormContext()

return (
<Controller
name="information.instagram"
control={control}
rules={{
required: false,
pattern: {
value: /^([a-zA-Z0-9._]+)$/,
message: 'Invalid Instagram username.',
},
}}
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
InputProps={{
startAdornment: (
<InputAdornment position="start" style={{ marginRight: '0px' }}>
<FontAwesomeIcon icon={faInstagram} />
<span style={{ paddingLeft: '8px' }}>instagram.com/</span>
</InputAdornment>
),
}}
error={!!error}
helperText={error?.message ? error.message : null}
label="Instagram"
margin="dense"
/>
)}
/>
)
}

export default Instagram
42 changes: 42 additions & 0 deletions src/components/ticker/form/Threads.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { faThreads } from '@fortawesome/free-brands-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { InputAdornment, TextField } from '@mui/material'
import { FC } from 'react'
import { Controller, useFormContext } from 'react-hook-form'

const Threads: FC = () => {
const { control } = useFormContext()

return (
<Controller
name="information.threads"
control={control}
rules={{
required: false,
pattern: {
value: /^@([a-zA-Z0-9._]+)$/,
message: 'Invalid Threads username. Must start with @',
},
}}
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
InputProps={{
startAdornment: (
<InputAdornment position="start" style={{ marginRight: '0px' }}>
<FontAwesomeIcon icon={faThreads} />
<span style={{ paddingLeft: '8px' }}>threads.net/</span>
</InputAdornment>
),
}}
error={!!error}
helperText={error?.message ? error.message : null}
label="Threads"
margin="dense"
/>
)}
/>
)
}

export default Threads
59 changes: 56 additions & 3 deletions src/components/ticker/form/TickerForm.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import sign from 'jwt-encode'
import { MemoryRouter } from 'react-router'
import { Ticker } from '../../../api/Ticker'
Expand All @@ -19,7 +20,7 @@ describe('TickerForm', () => {
return {
id: 1,
title: 'Ticker',
active: true,
active: false,
information: {},
location: {},
} as Ticker
Expand All @@ -42,8 +43,8 @@ describe('TickerForm', () => {
<MemoryRouter>
<AuthProvider>
<div>
<TickerForm ticker={ticker} id="1" callback={callback} />
<input name="Submit" type="submit" value="Submit" form="configureWebsites" />
<TickerForm ticker={ticker} id="tickerForm" callback={callback} />
<input name="Submit" type="submit" value="Submit" form="tickerForm" />
</div>
</AuthProvider>
</MemoryRouter>
Expand All @@ -57,4 +58,56 @@ describe('TickerForm', () => {
expect(screen.getByRole('textbox', { name: 'Title' })).toBeInTheDocument()
expect(screen.getByRole('checkbox', { name: 'Active' })).toBeInTheDocument()
})

it('should submit the form', async () => {
setup(ticker())

fetchMock.mockResponseOnce(JSON.stringify({ status: 'success' }))

await userEvent.click(screen.getByRole('checkbox', { name: 'Active' }))
await userEvent.clear(screen.getByRole('textbox', { name: 'Title' }))
await userEvent.type(screen.getByRole('textbox', { name: 'Title' }), 'New Ticker')
await userEvent.type(screen.getByRole('textbox', { name: 'Description' }), 'Description')
await userEvent.type(screen.getByRole('textbox', { name: 'Author' }), 'Author')
await userEvent.type(screen.getByRole('textbox', { name: 'Homepage' }), 'https://example.org')
await userEvent.type(screen.getByRole('textbox', { name: 'E-Mail' }), '[email protected]')
await userEvent.type(screen.getByRole('textbox', { name: 'Twitter' }), 'account')
await userEvent.type(screen.getByRole('textbox', { name: 'Facebook' }), 'account')
await userEvent.type(screen.getByRole('textbox', { name: 'Threads' }), '@account')
await userEvent.type(screen.getByRole('textbox', { name: 'Instagram' }), 'account')
await userEvent.type(screen.getByRole('textbox', { name: 'Telegram' }), 'account')
await userEvent.type(screen.getByRole('textbox', { name: 'Mastodon' }), 'https://mastodon.social/@account')
await userEvent.type(screen.getByRole('textbox', { name: 'Bluesky' }), 'https://bsky.app/profile/account.bsky.social')

await userEvent.click(screen.getByRole('button', { name: 'Submit' }))

expect(callback).toHaveBeenCalledTimes(1)
expect(fetchMock).toHaveBeenCalledTimes(1)
expect(fetchMock).toHaveBeenCalledWith('http://localhost:8080/v1/admin/tickers/1', {
body: JSON.stringify({
title: 'New Ticker',
active: true,
description: 'Description',
information: {
author: 'Author',
email: '[email protected]',
url: 'https://example.org',
twitter: 'account',
facebook: 'account',
threads: '@account',
instagram: 'account',
telegram: 'account',
mastodon: 'https://mastodon.social/@account',
bluesky: 'https://bsky.app/profile/account.bsky.social',
},
location: { lat: 0, lon: 0 },
}),
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
method: 'put',
})
})
})
14 changes: 14 additions & 0 deletions src/components/ticker/form/TickerForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import Bluesky from './Bluesky'
import Description from './Description'
import Email from './Email'
import Facebook from './Facebook'
import Instagram from './Instagram'
import Mastodon from './Mastodon'
import Telegram from './Telegram'
import Threads from './Threads'
import Title from './Title'
import Twitter from './Twitter'
import Url from './Url'
Expand All @@ -37,6 +39,8 @@ const TickerForm: FC<Props> = ({ callback, id, ticker }) => {
url: ticker?.information.url,
twitter: ticker?.information.twitter,
facebook: ticker?.information.facebook,
threads: ticker?.information.threads,
instagram: ticker?.information.instagram,
telegram: ticker?.information.telegram,
mastodon: ticker?.information.mastodon,
bluesky: ticker?.information.bluesky,
Expand Down Expand Up @@ -140,6 +144,16 @@ const TickerForm: FC<Props> = ({ callback, id, ticker }) => {
<Facebook />
</FormGroup>
</Grid>
<Grid size={{ sm: 6, xs: 12 }}>
<FormGroup>
<Threads />
</FormGroup>
</Grid>
<Grid size={{ sm: 6, xs: 12 }}>
<FormGroup>
<Instagram />
</FormGroup>
</Grid>
<Grid size={{ sm: 6, xs: 12 }}>
<FormGroup>
<Telegram />
Expand Down
4 changes: 3 additions & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// <reference types="vitest" />

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

// https://vitejs.dev/config/
export default defineConfig({
Expand All @@ -20,5 +20,7 @@ export default defineConfig({
provider: 'v8',
reporter: ['lcov'],
},
pool: 'threads',
testTimeout: 10000,
},
})

0 comments on commit 6514474

Please sign in to comment.