Skip to content

Commit

Permalink
fix login page content
Browse files Browse the repository at this point in the history
add documentation
  • Loading branch information
craigrbarnes committed Jan 30, 2025
1 parent ee89a8f commit 57be03c
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 29 deletions.
38 changes: 38 additions & 0 deletions docs/Configuration/Login.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Login Configuration Guide

The login page configuration consists of two main sections:
* Top Content
* Bottom Content

and example configuration:
```json
{
"topContent": [
{
"text": "Gen3 Data Commons",
"className": "text-center text-3xl font-bold"
},
{
"text": "DISCOVER, ANALYZE, AND SHARE DATA",
"className": "text-center text-xl font-medium"
}
],
"bottomContent": [
{
"type" : "textWithEmail",
"text": "If you have any questions about access or the registration process, please contact",
"email": "[email protected]",
"className": "text-center text-sm"
}
],
"image": "images/gene_side_texture.svg",
"showCredentialsLogin" : true
}

```

Both topContent and bottomContent are arrays of the [TextContent](../../packages/frontend/docs/components/TextContent.md) component.

* image: the side image for the login page
* showCredentialsLogin: is for development and allows logins using a credentials file instead of logging in which
usually will not work because fence will not allow redirects back to https://localhost
185 changes: 185 additions & 0 deletions packages/frontend/docs/components/TextContent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# TextContent Component Documentation

## Overview

The TextContent component is a versatile React component designed to render various types of text-based content with different formatting options. It supports multiple content types including plain text, HTML, Markdown, text arrays, and text with email or link attachments.

## Installation

```jsx
import TextContent, { ContentType } from './path/to/TextContent';
```

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| text | `string \| string[]` | Required | The content to be displayed. Can be a single string or an array of strings. |
| className | `string` | `'inline text-base-contrast-max font-medium margin-block-start-1 margin-block-end-1'` | Custom Tailwind CSS classes for styling the component. |
| type | `ContentType` | `ContentType.Text` | Determines how the content will be rendered. |
| email | `string` | `undefined` | Optional email address for TextWithEmail type. |
| link | `string` | `undefined` | Optional URL for TextWithLink type. |
| linkText | `string` | `undefined` | Optional display text for the link. |

## Content Types

The component supports six different content types through the `ContentType` enum:

### 1. Text (`ContentType.Text`)
- Basic text rendering
- Renders content in a simple `<div>` with a `<p>` tag
- Default content type if none specified

```jsx
<TextContent text="Hello, world!" />
```

### 2. Text Array (`ContentType.TextArray`)
- Renders an array of strings as separate paragraphs
- Each paragraph is wrapped in a `<p>` tag with `my-2` spacing
- Automatically generates unique keys using a hash function

```jsx
<TextContent
type={ContentType.TextArray}
text={["First paragraph", "Second paragraph"]}
/>
```

### 3. HTML (`ContentType.Html`)
- Renders HTML content using dangerouslySetInnerHTML
- Joins arrays into a single string if provided
- Wrapped in a `<p>` tag with custom styling

```jsx
<TextContent
type={ContentType.Html}
text="<strong>Bold</strong> and <em>italic</em> text"
/>
```

### 4. Markdown (`ContentType.Markdown`)
- Renders Markdown content using react-markdown
- Includes support for GitHub Flavored Markdown (GFM)
- Custom styling for paragraphs, lists, and list items
- Default text size of `text-lg` for paragraphs

```jsx
<TextContent
type={ContentType.Markdown}
text="# Header\n\nThis is **bold** text"
/>
```

### 5. Text With Email (`ContentType.TextWithEmail`)
- Combines text content with a clickable email link
- Email is appended to the text with proper formatting
- Uses Mantine's Anchor component for the email link

```jsx
<TextContent
type={ContentType.TextWithEmail}
text="Contact us at"
email="[email protected]"
/>
```

### 6. Text With Link (`ContentType.TextWithLink`)
- Combines text content with a clickable URL
- Optional custom link text
- Uses Mantine's Anchor component for the link

```jsx
<TextContent
type={ContentType.TextWithLink}
text="Visit our website at"
link="https://example.com"
linkText="Example.com"
/>
```

## Styling

The component uses Tailwind CSS for styling with a default className of:
```
inline text-base-contrast-max font-medium margin-block-start-1 margin-block-end-1
```

Custom styles can be added through the `className` prop and will be merged with default styles using `tailwind-merge`.

## Dependencies

The component requires the following dependencies:
- React
- react-markdown
- remark-gfm
- @mantine/core
- tailwind-merge

## Error Handling

- For TextWithLink type, displays "Link is not defined" if no link is provided
- Automatically converts text to string using toString() in default case
- Handles both string and string[] inputs gracefully

## Best Practices

1. **Content Type Selection**
- Use plain Text for simple string content
- Use TextArray for multiple paragraphs
- Use Markdown for formatted content
- Use HTML only when necessary due to security implications

2. **Styling**
- Prefer using Tailwind classes for styling
- Use className prop for custom styles
- Avoid inline styles

3. **Performance**
- Use TextArray for large content blocks
- Provide unique content to avoid unnecessary re-renders
- Consider memoization for frequently updated content

## Examples

### Basic Usage
```jsx
<TextContent text="Simple text content" />
```

### Markdown with Custom Styling
```jsx
<TextContent
type={ContentType.Markdown}
text="# Title\n\nContent with **bold** text"
className="prose dark:prose-invert"
/>
```

### Text Array with Custom Styling
```jsx
<TextContent
type={ContentType.TextArray}
text={["First paragraph", "Second paragraph"]}
className="text-lg font-serif"
/>
```

### Email Contact
```jsx
<TextContent
type={ContentType.TextWithEmail}
text="For support, please contact"
email="[email protected]"
/>
```

### External Link
```jsx
<TextContent
type={ContentType.TextWithLink}
text="Check out our documentation at"
link="https://docs.example.com"
linkText="our docs site"
/>
```
58 changes: 39 additions & 19 deletions packages/frontend/src/components/Content/TextContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,49 @@ import { hashCode } from '../../utils/hash';
import { twMerge } from 'tailwind-merge';
import { Anchor } from '@mantine/core';

/**
* Enum representing various content types for text-based data.
*
* Each content type corresponds to a specific format or structure of textual content.
*/
export enum ContentType {
Text = 'text',
TextArray = 'textArray',
Html = 'html',
Markdown = 'markdown',
TextWithEmail = 'textWithEmail',
TextWithLink = 'textWithLink',
Link = 'link',
Text = 'text', // a text string
TextArray = 'textArray', // a array of text, each is a paragraph
Html = 'html', // text content is HTML
Markdown = 'markdown', // text content is Markdown
TextWithEmail = 'textWithEmail', // text is a string and the email field is appended to it
TextWithLink = 'textWithLink', // test followed by a link
}

/**
* Interface representing the properties for rendering text content.
*/
export interface TextContentProps {
readonly text: string | string[];
readonly className?: string;
readonly type?: ContentType;
readonly email?: string;
readonly link?: string;
readonly linkText?: string;
readonly text: string | string[]; // text to show. Arrays of text will be inside of a html paragraph (i.e <p>) tag
readonly className?: string; // tailwind based styling to apply to the text content
readonly type?: ContentType; // type of content (see ContentType)
readonly email?: string; // email used for type = textWithEmail
readonly link?: string; // link used for type = textWithLink
readonly linkText?: string; // optional text for link
}

/**
* Renders textual content dynamically based on the provided type and additional properties.
*
* The `TextContent` function creates a user interface element conditioned on the type of input content, such as plain text, HTML, Markdown, text arrays, text with email links, or text with hyperlinks. It also provides default styling and customizable CSS class support.
*
* @param {Object} props - Properties for rendering the TextContent component.
* @param {string | string[]} props.text - The content to be displayed. It can be a single string or an array of strings.
* @param {string} [props.className='inline text-base-contrast-max font-medium margin-block-start-1 margin-block-end-1'] - Custom CSS classes to apply for styling. Defaults to a predefined inline style.
* @param {ContentType} [props.type=ContentType.Text] - Specifies the type of content being passed. Determines how the content will be rendered.
* @param {string} [props.email] - Optional email address to be rendered as a clickable "mailto" link when type is `ContentType.TextWithEmail`.
* @param {string} [props.link] - Optional URL to be rendered as a clickable hyperlink when type is `ContentType.TextWithLink`.
* @param {string} [props.linkText] - Optional link text to display instead of the raw URL when type is `ContentType.TextWithLink`.
* @returns {JSX.Element} A JSX element that renders the content dynamically based on the input type and properties.
*/
const TextContent = ({
text,
className = 'inline text-base-contrast-min font-medium margin-block-start-1 margin-block-end-1',
className = 'inline text-base-contrast-max font-medium margin-block-start-1 margin-block-end-1',
type = ContentType.Text,
email = undefined,
link = undefined,
Expand Down Expand Up @@ -64,9 +86,7 @@ const TextContent = ({
// define some formatting for the ai response
p(props: any) {
const { node, ...rest } = props;
return (
<p className="text-lg text-primary-contrast my-1" {...rest} />
);
return <p className="text-lg my-1" {...rest} />;
},
ol(props: any) {
const { node, ...rest } = props;
Expand All @@ -89,7 +109,7 @@ const TextContent = ({
}
case ContentType.TextWithEmail: {
const DEFAULT_STYLE =
'inline text-base-contrast-min font-medium margin-block-start-1 margin-block-end-1';
'inline text-base-contrast-max font-medium margin-block-start-1 margin-block-end-1';
const mergedClassname = className
? twMerge(DEFAULT_STYLE, className)
: DEFAULT_STYLE;
Expand All @@ -110,7 +130,7 @@ const TextContent = ({
}
case ContentType.TextWithLink: {
const DEFAULT_STYLE =
'inline text-base-contrast-min font-medium margin-block-start-1 margin-block-end-1';
'inline text-base-contrast-max font-medium margin-block-start-1 margin-block-end-1';
const mergedClassname = className
? twMerge(DEFAULT_STYLE, className)
: DEFAULT_STYLE;
Expand Down
6 changes: 5 additions & 1 deletion packages/frontend/src/components/Login/CredentialsLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ const CredentialsLogin = ({ handleLogin }: CredentialsLoginProps) => {
color="black"
size="md"
className="w-1/3"
label={<Text size="md">Authorize with credentials</Text>}
label={
<Text size="md" c="primary.4">
Authorize with credentials
</Text>
}
labelPosition="center"
/>
<Group>
Expand Down
13 changes: 8 additions & 5 deletions packages/frontend/src/components/Login/LoginPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React, { useCallback } from 'react';
import { useRouter } from 'next/router';
import { showNotification } from '@mantine/notifications';
import { Center, Stack } from '@mantine/core';
import TexturedSidePanel from '../Layout/TexturedSidePanel';
import LoginProvidersPanel from './LoginProvidersPanel';
import CredentialsLogin from './CredentialsLogin';
import TextContent from '../Content/TextContent';
import { LoginConfig } from './types';
import { GEN3_REDIRECT_URL } from '@gen3/core';
import ContactWithEmailContent from '../Content/ContactWithEmailContent';
import { isArray } from 'lodash';

const filterRedirect = (redirect: string | string[] | undefined) => {
Expand Down Expand Up @@ -68,10 +68,13 @@ const LoginPanel = (loginConfig: LoginConfig) => {
process.env.NODE_ENV === 'development' && (
<CredentialsLogin handleLogin={handleCredentialsLogin} />
)}

{bottomContent?.map((content, index) => (
<TextContent {...content} key={`bottomContent-${index}`} />
))}
<Center>
<Stack>
{bottomContent?.map((content, index) => (
<TextContent {...content} key={`bottomContent-${index}`} />
))}
</Stack>
</Center>
</div>
<TexturedSidePanel url={image} />
</div>
Expand Down
8 changes: 4 additions & 4 deletions packages/frontend/src/components/Login/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { TextContentProps } from '../Content/TextContent';

export interface Gen3LoginPanelConfig {
title: string;
subtitle: string;
text: string;
contact: string;
title: string; // Main title for Login page
subtitle: string; // a sub title
text: string; // text string below the login buttons
contact: string; // contact message
email: string;
image: string;
className: string;
Expand Down
8 changes: 8 additions & 0 deletions packages/tools/localDev/nginx/revproxy_nginx.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,13 @@ http {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

# proxy GWAS cohort-middleware
location /cohort-middleware/ {
proxy_pass https://$GEN3_REMOTE_API;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}

0 comments on commit 57be03c

Please sign in to comment.