1.105.0 • Published 2 years ago

spotter-eng-utils v1.105.0

Weekly downloads
-
License
ISC
Repository
bitbucket
Last release
2 years ago

Setting up in Vercel

  1. Choose a template or copy code from the next/example section
  2. Make sure vercel cli is installed - https://vercel.com/docs/cli
  3. Run vercel login
  4. Run vercel init
  5. Setup your environment variables https://vercel.com/spotter/{yourapp}/settings/environment-variables
    • Environment variables must have NEXT_PUBLIC_ prefix to be available on client and server sides
    • If you omit the NEXT_PUBLIC_, it will only be accessible on the server side
  6. To access your secrets for development, add this to your package.json or simply copy what's in the next/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/

  1. 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;
  1. 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

PropertyDescriptionOptions
noAuthWill allow the page to be public. Otherwise it will redirect user to login if not authenticated.true (default)false
LayoutThis 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
1.98.0

2 years ago

1.79.0

2 years ago

1.56.0

2 years ago

1.94.0

2 years ago

1.90.0

2 years ago

1.82.0

2 years ago

1.63.0

2 years ago

1.86.0

2 years ago

1.103.0

2 years ago

1.67.0

2 years ago

1.48.0

2 years ago

1.70.0

2 years ago

1.51.0

2 years ago

1.74.0

2 years ago

1.55.0

2 years ago

1.57.0

2 years ago

1.97.0

2 years ago

1.93.0

2 years ago

1.60.0

2 years ago

1.83.0

2 years ago

1.64.0

2 years ago

1.102.0

2 years ago

1.87.0

2 years ago

1.68.0

2 years ago

1.49.0

2 years ago

1.71.0

2 years ago

1.75.0

2 years ago

1.52.0

2 years ago

1.96.0

2 years ago

1.58.0

2 years ago

1.92.0

2 years ago

1.101.0

2 years ago

1.80.0

2 years ago

1.84.0

2 years ago

1.61.0

2 years ago

1.105.0

2 years ago

1.65.0

2 years ago

1.89.0

2 years ago

1.88.0

2 years ago

1.69.0

2 years ago

1.72.0

2 years ago

1.53.0

2 years ago

1.76.0

2 years ago

1.99.0

2 years ago

1.78.0

2 years ago

1.59.0

2 years ago

1.95.0

2 years ago

1.91.0

2 years ago

1.100.0

2 years ago

1.81.0

2 years ago

1.62.0

2 years ago

1.104.0

2 years ago

1.85.0

2 years ago

1.66.0

2 years ago

1.73.0

2 years ago

1.50.0

2 years ago

1.77.0

2 years ago

1.54.0

2 years ago

1.47.0

2 years ago

1.46.0

2 years ago

1.45.0

2 years ago

1.44.0

2 years ago

1.43.0

2 years ago

1.42.0

2 years ago

1.41.0

2 years ago

1.40.0

2 years ago

1.39.0

2 years ago

1.38.0

2 years ago

1.37.0

2 years ago

1.36.0

2 years ago

1.35.0

2 years ago

1.34.0

2 years ago

1.33.0

2 years ago

1.32.0

2 years ago

1.31.0

2 years ago

1.30.0

2 years ago

1.29.0

2 years ago

1.28.0

2 years ago

1.27.0

2 years ago

1.26.0

2 years ago

1.25.0

2 years ago

1.24.0

2 years ago

1.23.0

2 years ago

1.22.0

2 years ago

1.21.0

2 years ago

1.20.0

2 years ago

1.19.0

2 years ago

1.18.0

2 years ago

1.17.0

2 years ago

1.16.0

2 years ago

1.15.0

2 years ago

1.14.0

2 years ago

1.13.0

2 years ago

1.12.0

2 years ago

1.11.0

2 years ago

1.10.0

2 years ago

1.9.0

2 years ago

1.8.0

2 years ago

1.7.0

2 years ago

1.6.0

2 years ago

1.5.0

2 years ago

1.4.0

2 years ago

1.3.0

2 years ago

1.2.0

2 years ago

1.1.0

2 years ago