added modal to select source documentation

This commit is contained in:
TaylorS15 2023-02-19 15:26:27 -05:00
parent 63859a814b
commit 5902ca0201
5 changed files with 191 additions and 3 deletions

View File

@ -6,8 +6,12 @@ import Info from './assets/info.svg';
import Link from './assets/link.svg';
import { ActiveState } from './models/misc';
import APIKeyModal from './preferences/APIKeyModal';
import SelectDocsModal from './preferences/SelectDocsModal';
import { useSelector } from 'react-redux';
import { selectApiKeyStatus } from './preferences/preferenceSlice';
import {
selectApiKeyStatus,
selectSelectedDocsStatus,
} from './preferences/preferenceSlice';
import { useState } from 'react';
//TODO - Need to replace Chat button to open secondary nav with scrollable past chats option and new chat at top
@ -24,6 +28,11 @@ export default function Navigation({
const [apiKeyModalState, setApiKeyModalState] = useState<ActiveState>(
isApiKeySet ? 'INACTIVE' : 'ACTIVE',
);
const isSelectedDocsSet = useSelector(selectSelectedDocsStatus);
const [selectedDocsModalState, setSelectedDocsModalState] =
useState<ActiveState>(isSelectedDocsSet ? 'INACTIVE' : 'ACTIVE');
return (
<>
<div
@ -49,7 +58,7 @@ export default function Navigation({
</div>
<div className="flex-grow border-b-2 border-gray-100"></div>
<div className="flex h-16 flex-col border-b-2 border-gray-100">
<div className="flex flex-col gap-2 border-b-2 border-gray-100 py-2">
<div
className="my-auto mx-4 flex h-12 cursor-pointer gap-4 rounded-md hover:bg-gray-100"
onClick={() => {
@ -59,6 +68,18 @@ export default function Navigation({
<img src={Key} alt="key" className="ml-2 w-6" />
<p className="my-auto text-eerie-black">Reset Key</p>
</div>
<div
className="my-auto mx-4 flex h-12 cursor-pointer gap-4 rounded-md hover:bg-gray-100"
onClick={() => {
setSelectedDocsModalState('ACTIVE');
}}
>
<img src={Link} alt="key" className="ml-2 w-5" />
<p className="my-auto text-eerie-black">
Select Source Documentation
</p>
</div>
</div>
<div className="flex h-48 flex-col border-b-2 border-gray-100">
@ -87,11 +108,17 @@ export default function Navigation({
>
<img src={Hamburger} alt="menu toggle" className="w-7" />
</button>
<APIKeyModal
modalState={apiKeyModalState}
setModalState={setApiKeyModalState}
isCancellable={isApiKeySet}
/>
<SelectDocsModal
modalState={selectedDocsModalState}
setModalState={setSelectedDocsModalState}
isCancellable={isSelectedDocsSet}
/>
</>
);
}

18
frontend/src/api/docs.ts Normal file
View File

@ -0,0 +1,18 @@
import { Doc } from '../models/misc';
export async function getDocs(): Promise<Array<Doc>> {
//Fetch default source docs
const response = await fetch(
'https://d3dg1063dc54p9.cloudfront.net/combined.json',
);
const data = await response.json();
//Create array of Doc objects
const docs: Array<Doc> = [];
data.forEach((doc: Doc) => {
docs.push(doc);
});
return docs;
}

View File

@ -3,3 +3,14 @@ export type ActiveState = 'ACTIVE' | 'INACTIVE';
export type User = {
avatar: string;
};
export type Doc = {
name: string;
language: string;
version: string;
description: string;
fullName: string;
dat: string;
docLink: string;
model: string;
};

View File

@ -0,0 +1,122 @@
import { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { ActiveState, Doc } from '../models/misc';
import { setSelectedDocs, selectSelectedDocs } from './preferenceSlice';
import { getDocs } from '../api/docs';
export default function APIKeyModal({
modalState,
setModalState,
isCancellable = true,
}: {
modalState: ActiveState;
setModalState: (val: ActiveState) => void;
isCancellable?: boolean;
}) {
const dispatch = useDispatch();
const [isError, setIsError] = useState(false);
const [docs, setDocs] = useState<Doc[]>([]);
const [localSelectedDocs, setLocalSelectedDocs] = useState<Doc | null>(null);
const [isDocsListOpen, setIsDocsListOpen] = useState(false);
function handleSubmit() {
if (!localSelectedDocs) {
setIsError(true);
} else {
dispatch(setSelectedDocs(localSelectedDocs));
setModalState('INACTIVE');
setLocalSelectedDocs(null);
setIsError(false);
}
}
function handleCancel() {
setSelectedDocs(null);
setIsError(false);
setModalState('INACTIVE');
}
useEffect(() => {
async function requestDocs() {
const data = await getDocs();
setDocs(data);
}
requestDocs();
}, []);
return (
<div
className={`${
modalState === 'ACTIVE' ? 'visible' : 'hidden'
} absolute z-30 h-screen w-screen bg-gray-alpha`}
>
<article className="mx-auto mt-24 flex w-[90vw] max-w-lg flex-col gap-4 rounded-lg bg-white p-6 shadow-lg">
<p className="text-xl text-jet">Select Source Documentation</p>
<p className="text-lg leading-5 text-gray-500">
Please select the library of documentation that you would like to use
with our app.
</p>
<div className="relative">
<div
className="h-10 w-full cursor-pointer border-b-2"
onClick={() => setIsDocsListOpen(!isDocsListOpen)}
>
{!localSelectedDocs ? (
<p className="py-3 text-gray-500">Select</p>
) : (
<p className="py-3">
{localSelectedDocs.name} {localSelectedDocs.version}
</p>
)}
</div>
{isDocsListOpen && (
<div className="absolute top-10 left-0 h-52 w-full overflow-y-scroll bg-white">
{docs.map((doc, index) => {
if (doc.model) {
return (
<div
key={index}
onClick={() => {
setLocalSelectedDocs(doc);
setIsDocsListOpen(false);
}}
className="h-10 w-full cursor-pointer border-x-2 border-b-2 hover:bg-gray-100"
>
<p className="ml-5 py-3">
{doc.name} {doc.version}
</p>
</div>
);
}
})}
</div>
)}
</div>
<div className="flex flex-row-reverse">
{isCancellable && (
<button
onClick={() => handleCancel()}
className="ml-5 h-10 w-20 rounded-lg border border-violet-700 bg-white text-violet-800 transition-all hover:bg-violet-700 hover:text-white"
>
Cancel
</button>
)}
<button
onClick={() => {
handleSubmit();
}}
className="ml-auto h-10 w-20 rounded-lg bg-violet-800 text-white transition-all hover:bg-violet-700"
>
Save
</button>{' '}
{isError && (
<p className="mr-auto text-sm text-red-500">
Please select source documentation.
</p>
)}
</div>
</article>
</div>
);
}

View File

@ -1,12 +1,15 @@
import { createSlice } from '@reduxjs/toolkit';
import { Doc } from '../models/misc';
import store from '../store';
interface Preference {
apiKey: string;
selectedDocs: Doc | null;
}
const initialState: Preference = {
apiKey: '',
selectedDocs: null,
};
export const prefSlice = createSlice({
@ -16,10 +19,13 @@ export const prefSlice = createSlice({
setApiKey: (state, action) => {
state.apiKey = action.payload;
},
setSelectedDocs: (state, action) => {
state.selectedDocs = action.payload;
},
},
});
export const { setApiKey } = prefSlice.actions;
export const { setApiKey, setSelectedDocs } = prefSlice.actions;
export default prefSlice.reducer;
type RootState = ReturnType<typeof store.getState>;
@ -27,3 +33,7 @@ type RootState = ReturnType<typeof store.getState>;
export const selectApiKey = (state: RootState) => state.preference.apiKey;
export const selectApiKeyStatus = (state: RootState) =>
!!state.preference.apiKey;
export const selectSelectedDocs = (state: RootState) =>
state.preference.selectedDocs;
export const selectSelectedDocsStatus = (state: RootState) =>
!!state.preference.selectedDocs;