spotter-eng-utils
v1.105.0
Published
Spotter Utils
Downloads
27
Readme
Setting up in Vercel
- Choose a template or copy code from the
next/example
section - Make sure
vercel cli
is installed - https://vercel.com/docs/cli - Run
vercel login
- Run
vercel init
- Setup your environment variables
https://vercel.com/spotter/{yourapp}/settings/environment-variables
- Environment variables must have
NEXT_PUBLIC_
prefix to be available onclient
andserver
sides - If you omit the
NEXT_PUBLIC_
, it will only be accessible on theserver
side
- Environment variables must have
- To access your secrets for development, add this to your
package.json
or simply copy what's in thenext/example
:vercel pull && cp .vercel/.env.development.local .env
Setup NextJS App using this module -
All of these code snippets are found under nextjs/example
If you have conflicts with AWS Code Artifact, you may have to reset your npm registry: npm config set registry https://registry.npmjs.org/
- Replace
_app.js
contents with:
import { store } from '@/store';
import '@/styles/globals.css';
import { Provider } from 'react-redux';
import { appGetInitialProps, MyAppSetup } from 'spotter-eng-utils/nextjs/authentication/bootstrapApp';
import { toTitleCase } from 'spotter-eng-utils/nextjs/utils';
const { name } = require('../package.json');
const ExtraHeaderComponent = () => {
// Extra header components here
return <></>;
};
function MyApp({ Component, pageProps, startupProps }) {
const headerData = {
title: 'SpotterLabs',
subTitle: toTitleCase(name, true),
component: <ExtraHeaderComponent />,
};
return <Provider store={store}>{MyAppSetup(Component, pageProps, startupProps, headerData, store)}</Provider>;
}
MyApp.getInitialProps = async appContext => {
return await appGetInitialProps(appContext);
};
export default MyApp;
- Create a file called
login.js
at the same level as_app.js
and paste:
import SpotterLogin from 'spotter-eng-utils/nextjs/authentication/googleLogin/login';
const Login = props => {
const { serverUrl } = props;
return (
<SpotterLogin
title={'Your Login title goes here'}
serverUrl={serverUrl}
clientId={'Your Google Client ID goes here'}
authServerURI={`${backendAuthDomainGoesHere}/api/login/google`}
/>
);
};
export default Login;
Page Property Overrides
| Property | Description | Options | | -------- | ---------------------------------------------------------------------------------------------------------------------- | ----------------------- | | noAuth | Will allow the page to be public. Otherwise it will redirect user to login if not authenticated. | true (default)false | | Layout | This will allow you to create & set a custom layout for the current page. While running needed code behind the scenes. | |
Example:
const Home = () => {
return <div>Open unauthenticated Landing Page</div>;
};
Home.noAuth = true;
export default Home;
REST Calls
REST calls should be setup in this structure. Please see the sample code in next/example
project
│ README.md
│ ...
└───pages
│ ...
│
└───services
│───client
│ * index.js - This should setup your axios instances
│ * users.js - This could get your userProfile or updateProfile
│───server
│ * index.js - This should setup your axios instances
│ * users.js - This could get your userProfile
Example Client Side Call
useEffect(() => {
const [clientSideUserProfile, setClientSideUserProfile] = useState(null);
const getProfile = async () => {
const profile = await UserClientSideService.portal.getProfile();
setClientSideUserProfile(profile);
};
getProfile().catch(console.error);
}, []);
Example Server Side Call
const Home = ({ serverSideUserProfile }) => {
return (
<div>
<pre>{JSON.stringify(clientSideUserProfile, null, 2)}</pre>
</div>
);
};
export const getServerSideProps = async context => {
const profile = await UserServerSideService.portal.getProfile(context);
return {
props: { serverSideUserProfile: profile },
};
};
Streaming AI Calls via Polling - (Depends on backend implementation)
Component:
import { useAICallPoller } from 'spotter-eng-utils/nextjs/streaming/aiCalls';
import { GPTModelContext } from 'spotter-eng-utils/nextjs/context';
const Home = ({ user }) => {
const dispatch = useDispatch();
const [userInput, setUserInput] = useState({
title: '',
summary: '',
});
// Current gptModel dropdown selection
const { gptModel } = useContext(GPTModelContext);
// Create record reducer
const createdTitle = useSelector(state => state.createdTitle);
// Fetch record reducer
const titleResults = useSelector(state => state.titleResults);
// Poller - kicks off when the create record dispatch is triggered
// polling is true/false so you can conditionally render elements.
const polling = useAICallPoller({
createReducerName: 'createdTitle', // name variable in create slice
pollingReducerName: 'titleResults', // name variable in fetch slice
intervalRate: 1000, // How often do you want to poll - time is in milliseconds
pollingSlice: getTitle, // asyncThunk in fetch slice
});
const executeAICall = () => {
dispatch(createTitle({ ...userInput, gptModel: gptModel.key }));
};
return <button onClick={executeAICall}>Stream My results</button>;
};
Create Object Slice
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { UserClientSideService } from '../../../services/client/calls';
const name = 'createTitle';
export const createTitle = createAsyncThunk(
name,
async (data, { dispatch, getState, rejectWithValue, fulfillWithValue }) => {
dispatch({ type: 'getTitle/reset' }); // Reset the fetch - need this so the polling terminator fn won't read last slice's values
try {
return await UserClientSideService.rnd.explode({
title: data.title,
title_summary: data.summary,
});
} catch (err) {
console.error(err);
dispatch({ type: 'bannerMessage/errored', payload: 'Custom Failure message.' });
rejectWithValue(err);
}
},
);
export const title = createSlice({
name: name,
initialState: {
data: {},
loading: false,
errored: false,
fulfilled: false,
},
reducers: {},
extraReducers: builder => {
builder.addCase(createTitle.pending, state => {
state.loading = true;
state.errored = false;
state.fulfilled = false;
state.data = {};
});
builder.addCase(createTitle.rejected, state => {
state.loading = false;
state.errored = true;
state.data = {};
});
builder.addCase(createTitle.fulfilled, (state, action) => {
state.loading = false;
state.errored = false;
state.fulfilled = true;
state.data = action.payload;
});
},
});
export default title.reducer;
Fetch Item Slice - This is the slice that will be polled
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { UserClientSideService } from '../../../services/client/calls';
const name = 'getTitle';
export const getTitle = createAsyncThunk(
name,
async (id, { dispatch, getState, rejectWithValue, fulfillWithValue }) => {
try {
return await UserClientSideService.rnd.getTitle(id);
} catch (err) {
console.error(err);
dispatch({ type: 'bannerMessage/errored', payload: 'Failed to fetch title.' });
rejectWithValue(err);
}
},
);
export const currentTitle = createSlice({
name: name,
initialState: {
data: {},
loading: false,
errored: false,
fulfilled: false,
},
reducers: {
// Called from the create object's createAsyncThunk so you can do subsequent polling
reset: (state, action) => {
state.data = {};
state.loading = false;
state.errored = false;
state.fulfilled = false;
},
},
extraReducers: builder => {
builder.addCase(getTitle.pending, state => {
state.loading = true;
state.errored = false;
state.fulfilled = false;
});
builder.addCase(getTitle.rejected, state => {
state.loading = false;
state.errored = true;
});
builder.addCase(getTitle.fulfilled, (state, action) => {
state.loading = false;
state.errored = false;
state.fulfilled = true;
state.data = action.payload;
});
},
});
export default currentTitle.reducer;
Setup Vercel
Choose https://vercel.com/docs/cli
next.config ->
/\*_ @type {import('next').NextConfig} _/;
const nextConfig = {
// reactStrictMode: true,
transpilePackages: ['spotter-eng-utils', '@types/google.accounts'],
};
module.exports = nextConfig;
Debugging
Go to the Debug panel (Ctrl+Shift+D on Windows/Linux, ⇧+⌘+D on macOS), select a launch configuration, then press F5 or select Debug: Start Debugging from the Command Palette to start your debugging session.
Tracking
GoogleAnalytics
- You can update and extend this component in
nextjs/components/tracking/googleAnalytics
HotJar
- You can update and extend this component in
nextjs/components/tracking/hotjar