Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbbc411823 | ||
|
|
72986fa192 | ||
|
|
cb4671c3a0 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,3 +1,8 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
*/node_modules/
|
*/node_modules/
|
||||||
*/build/
|
*/build/
|
||||||
|
|
||||||
|
**/node_modules/
|
||||||
|
**/build/
|
||||||
|
.DS_Store
|
||||||
|
.env
|
||||||
2
502.html
2
502.html
@ -129,7 +129,7 @@
|
|||||||
<p class="tip">The application is currently launching. The page will automatically refresh once site is
|
<p class="tip">The application is currently launching. The page will automatically refresh once site is
|
||||||
available.</p>
|
available.</p>
|
||||||
<div class="project-info">
|
<div class="project-info">
|
||||||
<h2>Build SaaS app that analysis stock in Nigeria</h2>
|
<h2>StocksageAI</h2>
|
||||||
<p>AI-powered SaaS for stock analysis and recommendations.</p>
|
<p>AI-powered SaaS for stock analysis and recommendations.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="loader-container">
|
<div class="loader-container">
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
# Build SaaS app that analysis stock in Nigeria
|
# StocksageAI
|
||||||
|
|
||||||
## This project was generated by [Flatlogic Platform](https://flatlogic.com).
|
## This project was generated by [Flatlogic Platform](https://flatlogic.com).
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1,4 +1,4 @@
|
|||||||
#Build SaaS app that analysis stock in Nigeria - template backend,
|
#StocksageAI - template backend,
|
||||||
|
|
||||||
#### Run App on local machine:
|
#### Run App on local machine:
|
||||||
|
|
||||||
@ -38,10 +38,10 @@
|
|||||||
|
|
||||||
- Type this command to creating a new database.
|
- Type this command to creating a new database.
|
||||||
|
|
||||||
- `postgres=> CREATE DATABASE db_build_saas_app_that_analysis_stock_in_nigeria;`
|
- `postgres=> CREATE DATABASE db_stocksageai;`
|
||||||
|
|
||||||
- Then give that new user privileges to the new database then quit the `psql`.
|
- Then give that new user privileges to the new database then quit the `psql`.
|
||||||
- `postgres=> GRANT ALL PRIVILEGES ON DATABASE db_build_saas_app_that_analysis_stock_in_nigeria TO admin;`
|
- `postgres=> GRANT ALL PRIVILEGES ON DATABASE db_stocksageai TO admin;`
|
||||||
- `postgres=> \q`
|
- `postgres=> \q`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "buildsaasappthatanalysisstockinnigeria",
|
"name": "stocksageai",
|
||||||
"description": "Build SaaS app that analysis stock in Nigeria - template backend",
|
"description": "StocksageAI - template backend",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npm run db:migrate && npm run db:seed && npm run watch",
|
"start": "npm run db:migrate && npm run db:seed && npm run watch",
|
||||||
"db:migrate": "sequelize-cli db:migrate",
|
"db:migrate": "sequelize-cli db:migrate",
|
||||||
@ -19,6 +19,8 @@
|
|||||||
"express": "4.18.2",
|
"express": "4.18.2",
|
||||||
"formidable": "1.2.2",
|
"formidable": "1.2.2",
|
||||||
"helmet": "4.1.1",
|
"helmet": "4.1.1",
|
||||||
|
"yahoo-finance2": "^2.0.0",
|
||||||
|
"node-cron": "^3.10.0",
|
||||||
"json2csv": "^5.0.7",
|
"json2csv": "^5.0.7",
|
||||||
"jsonwebtoken": "8.5.1",
|
"jsonwebtoken": "8.5.1",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
|
|||||||
@ -3,7 +3,7 @@ const os = require('os');
|
|||||||
const config = {
|
const config = {
|
||||||
gcloud: {
|
gcloud: {
|
||||||
bucket: 'fldemo-files',
|
bucket: 'fldemo-files',
|
||||||
hash: 'ee24f1c4218f76f2439ec343363a5eab',
|
hash: 'afeefb9d49f5b7977577876b99532ac7',
|
||||||
},
|
},
|
||||||
bcrypt: {
|
bcrypt: {
|
||||||
saltRounds: 12,
|
saltRounds: 12,
|
||||||
@ -36,7 +36,7 @@ const config = {
|
|||||||
},
|
},
|
||||||
uploadDir: os.tmpdir(),
|
uploadDir: os.tmpdir(),
|
||||||
email: {
|
email: {
|
||||||
from: 'Build SaaS app that analysis stock in Nigeria <app@flatlogic.app>',
|
from: 'StocksageAI <app@flatlogic.app>',
|
||||||
host: 'email-smtp.us-east-1.amazonaws.com',
|
host: 'email-smtp.us-east-1.amazonaws.com',
|
||||||
port: 587,
|
port: 587,
|
||||||
auth: {
|
auth: {
|
||||||
|
|||||||
@ -13,7 +13,7 @@ module.exports = {
|
|||||||
username: 'postgres',
|
username: 'postgres',
|
||||||
dialect: 'postgres',
|
dialect: 'postgres',
|
||||||
password: '',
|
password: '',
|
||||||
database: 'db_build_saas_app_that_analysis_stock_in_nigeria',
|
database: 'db_stocksageai',
|
||||||
host: process.env.DB_HOST || 'localhost',
|
host: process.env.DB_HOST || 'localhost',
|
||||||
logging: console.log,
|
logging: console.log,
|
||||||
seederStorage: 'sequelize',
|
seederStorage: 'sequelize',
|
||||||
|
|||||||
@ -107,7 +107,7 @@ const StocksData = [
|
|||||||
|
|
||||||
score: 85.5,
|
score: 85.5,
|
||||||
|
|
||||||
market: 'nigeria',
|
market: 'us',
|
||||||
|
|
||||||
// type code here for "relation_many" field
|
// type code here for "relation_many" field
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ const StocksData = [
|
|||||||
|
|
||||||
score: 78.3,
|
score: 78.3,
|
||||||
|
|
||||||
market: 'us',
|
market: 'nigeria',
|
||||||
|
|
||||||
// type code here for "relation_many" field
|
// type code here for "relation_many" field
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ const StocksData = [
|
|||||||
|
|
||||||
score: 92.1,
|
score: 92.1,
|
||||||
|
|
||||||
market: 'nigeria',
|
market: 'us',
|
||||||
|
|
||||||
// type code here for "relation_many" field
|
// type code here for "relation_many" field
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ const StocksData = [
|
|||||||
|
|
||||||
score: 88.7,
|
score: 88.7,
|
||||||
|
|
||||||
market: 'us',
|
market: 'nigeria',
|
||||||
|
|
||||||
// type code here for "relation_many" field
|
// type code here for "relation_many" field
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ const StocksData = [
|
|||||||
|
|
||||||
const SubscriptionsData = [
|
const SubscriptionsData = [
|
||||||
{
|
{
|
||||||
type: 'premium',
|
type: 'freemium',
|
||||||
|
|
||||||
start_date: new Date('2023-10-01T00:00:00Z'),
|
start_date: new Date('2023-10-01T00:00:00Z'),
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ const SubscriptionsData = [
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
type: 'premium',
|
type: 'freemium',
|
||||||
|
|
||||||
start_date: new Date('2023-10-01T00:00:00Z'),
|
start_date: new Date('2023-10-01T00:00:00Z'),
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ const SubscriptionsData = [
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
type: 'premium',
|
type: 'corporate',
|
||||||
|
|
||||||
start_date: new Date('2023-10-01T00:00:00Z'),
|
start_date: new Date('2023-10-01T00:00:00Z'),
|
||||||
|
|
||||||
@ -215,19 +215,19 @@ const SubscriptionsData = [
|
|||||||
|
|
||||||
const OrganizationsData = [
|
const OrganizationsData = [
|
||||||
{
|
{
|
||||||
name: 'Noam Chomsky',
|
name: 'Max von Laue',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'Karl Landsteiner',
|
name: 'Archimedes',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'William Harvey',
|
name: 'Gustav Kirchhoff',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'Rudolf Virchow',
|
name: 'George Gaylord Simpson',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -47,9 +47,9 @@ const options = {
|
|||||||
openapi: '3.0.0',
|
openapi: '3.0.0',
|
||||||
info: {
|
info: {
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
title: 'Build SaaS app that analysis stock in Nigeria',
|
title: 'StocksageAI',
|
||||||
description:
|
description:
|
||||||
'Build SaaS app that analysis stock in Nigeria Online REST API for Testing and Prototyping application. You can perform all major operations with your entities - create, delete and etc.',
|
'StocksageAI Online REST API for Testing and Prototyping application. You can perform all major operations with your entities - create, delete and etc.',
|
||||||
},
|
},
|
||||||
servers: [
|
servers: [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -12,6 +12,29 @@ const { parse } = require('json2csv');
|
|||||||
|
|
||||||
const { checkCrudPermissions } = require('../middlewares/check-permissions');
|
const { checkCrudPermissions } = require('../middlewares/check-permissions');
|
||||||
|
|
||||||
|
// Market data endpoints
|
||||||
|
const marketDataService = require('../services/marketDataService');
|
||||||
|
|
||||||
|
// Get historical price data for different ranges
|
||||||
|
router.get('/:id/price-history', wrapAsync(async (req, res) => {
|
||||||
|
const stock = await StocksDBApi.findBy({ id: req.params.id });
|
||||||
|
if (!stock) {
|
||||||
|
return res.status(404).send({ message: 'Stock not found' });
|
||||||
|
}
|
||||||
|
const range = req.query.range || 'monthly';
|
||||||
|
const data = await marketDataService.getHistoricalPrices(stock.ticker, range);
|
||||||
|
res.status(200).send(data);
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Get current market price
|
||||||
|
router.get('/:id/price-current', wrapAsync(async (req, res) => {
|
||||||
|
const stock = await StocksDBApi.findBy({ id: req.params.id });
|
||||||
|
if (!stock) {
|
||||||
|
return res.status(404).send({ message: 'Stock not found' });
|
||||||
|
}
|
||||||
|
const price = await marketDataService.getCurrentPrice(stock.ticker);
|
||||||
|
res.status(200).send({ price });
|
||||||
|
}));
|
||||||
router.use(checkCrudPermissions('stocks'));
|
router.use(checkCrudPermissions('stocks'));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
32
backend/src/services/marketDataService.js
Normal file
32
backend/src/services/marketDataService.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
const yahooFinance = require('yahoo-finance2').default;
|
||||||
|
|
||||||
|
async function getCurrentPrice(ticker) {
|
||||||
|
const quote = await yahooFinance.quote(ticker);
|
||||||
|
return quote.regularMarketPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getHistoricalPrices(ticker, range) {
|
||||||
|
const now = new Date();
|
||||||
|
let days;
|
||||||
|
switch (range) {
|
||||||
|
case 'daily': days = 1; break;
|
||||||
|
case 'weekly': days = 7; break;
|
||||||
|
case 'monthly': days = 30; break;
|
||||||
|
case '3m': days = 90; break;
|
||||||
|
case '6m': days = 180; break;
|
||||||
|
case '1y': days = 365; break;
|
||||||
|
case '3y': days = 365 * 3; break;
|
||||||
|
case '5y': days = 365 * 5; break;
|
||||||
|
default: days = 30;
|
||||||
|
}
|
||||||
|
const from = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
|
||||||
|
const options = { period1: from, period2: now, interval: '1d' };
|
||||||
|
const result = await yahooFinance.historical(ticker, options);
|
||||||
|
// Return array of { date, price }
|
||||||
|
return result.map(item => ({ date: item.date, price: item.close }));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getCurrentPrice,
|
||||||
|
getHistoricalPrices,
|
||||||
|
};
|
||||||
@ -1,6 +1,6 @@
|
|||||||
const errors = {
|
const errors = {
|
||||||
app: {
|
app: {
|
||||||
title: 'Build SaaS app that analysis stock in Nigeria',
|
title: 'StocksageAI',
|
||||||
},
|
},
|
||||||
|
|
||||||
auth: {
|
auth: {
|
||||||
|
|||||||
@ -25,7 +25,7 @@ services:
|
|||||||
- ./data/db:/var/lib/postgresql/data
|
- ./data/db:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_HOST_AUTH_METHOD=trust
|
- POSTGRES_HOST_AUTH_METHOD=trust
|
||||||
- POSTGRES_DB=db_build_saas_app_that_analysis_stock_in_nigeria
|
- POSTGRES_DB=db_stocksageai
|
||||||
ports:
|
ports:
|
||||||
- "5432:5432"
|
- "5432:5432"
|
||||||
logging:
|
logging:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Build SaaS app that analysis stock in Nigeria
|
# StocksageAI
|
||||||
|
|
||||||
## This project was generated by Flatlogic Platform.
|
## This project was generated by Flatlogic Platform.
|
||||||
|
|
||||||
|
|||||||
1
frontend/json/runtimeError.json
Normal file
1
frontend/json/runtimeError.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@ -76,9 +76,7 @@ export default function AsideMenuLayer({
|
|||||||
>
|
>
|
||||||
<div className='text-center flex-1 lg:text-left lg:pl-6 xl:text-center xl:pl-0'>
|
<div className='text-center flex-1 lg:text-left lg:pl-6 xl:text-center xl:pl-0'>
|
||||||
<Link href={'/home'}>
|
<Link href={'/home'}>
|
||||||
<b className='font-black'>
|
<b className='font-black'>StocksageAI</b>
|
||||||
Build SaaS app that analysis stock in Nigeria
|
|
||||||
</b>
|
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{organizationName && <p>{organizationName}</p>}
|
{organizationName && <p>{organizationName}</p>}
|
||||||
|
|||||||
@ -17,9 +17,9 @@ export default function WebSiteFooter({ projectName }: WebSiteFooterProps) {
|
|||||||
const borders = useAppSelector((state) => state.style.borders);
|
const borders = useAppSelector((state) => state.style.borders);
|
||||||
const websiteHeder = useAppSelector((state) => state.style.websiteHeder);
|
const websiteHeder = useAppSelector((state) => state.style.websiteHeder);
|
||||||
|
|
||||||
const style = FooterStyle.WITH_PROJECT_NAME;
|
const style = FooterStyle.WITH_PAGES;
|
||||||
|
|
||||||
const design = FooterDesigns.DEFAULT_DESIGN;
|
const design = FooterDesigns.DESIGN_DIVERSITY;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -19,7 +19,7 @@ export default function WebSiteHeader({ projectName }: WebSiteHeaderProps) {
|
|||||||
|
|
||||||
const style = HeaderStyle.PAGES_RIGHT;
|
const style = HeaderStyle.PAGES_RIGHT;
|
||||||
|
|
||||||
const design = HeaderDesigns.DESIGN_DIVERSITY;
|
const design = HeaderDesigns.DEFAULT_DESIGN;
|
||||||
return (
|
return (
|
||||||
<header id='websiteHeader' className='overflow-hidden'>
|
<header id='websiteHeader' className='overflow-hidden'>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -140,9 +140,8 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
|||||||
setStepsEnabled(false);
|
setStepsEnabled(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const title = 'Build SaaS app that analysis stock in Nigeria';
|
const title = 'StocksageAI';
|
||||||
const description =
|
const description = 'StocksageAI generated by Flatlogic';
|
||||||
'Build SaaS app that analysis stock in Nigeria generated by Flatlogic';
|
|
||||||
const url = 'https://flatlogic.com/';
|
const url = 'https://flatlogic.com/';
|
||||||
const image = `https://flatlogic.com/logo.svg`;
|
const image = `https://flatlogic.com/logo.svg`;
|
||||||
const imageWidth = '1920';
|
const imageWidth = '1920';
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import AboutUsSection from '../components/WebPageComponents/AboutUsComponent';
|
|||||||
export default function WebSite() {
|
export default function WebSite() {
|
||||||
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
||||||
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
||||||
const projectName = 'Build SaaS app that analysis stock in Nigeria';
|
const projectName = 'StocksageAI';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const darkElement = document.querySelector('body .dark');
|
const darkElement = document.querySelector('body .dark');
|
||||||
@ -129,19 +129,14 @@ export default function WebSite() {
|
|||||||
return (
|
return (
|
||||||
<div className='flex flex-col min-h-screen'>
|
<div className='flex flex-col min-h-screen'>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{`StockSageAI - Discover Undervalued Stocks with AI Insights`}</title>
|
<title>{`StocksageAI - Discover Undervalued Stocks with AI Insights`}</title>
|
||||||
<meta
|
|
||||||
name='description'
|
|
||||||
content={`Explore StockSageAI, the AI-powered platform that analyzes stocks in Nigeria and US markets using fundamental, technical, and sentiment data to identify undervalued stocks poised for growth.`}
|
content={`Explore StockSageAI, the AI-powered platform that analyzes stocks in Nigeria and US markets using fundamental, technical, and sentiment data to identify undervalued stocks poised for growth.`}
|
||||||
/>
|
content={`Explore StocksageAI, the AI-powered platform that analyzes stocks in Nigeria and US markets using fundamental, technical, and sentiment data to identify undervalued stocks poised for growth.`}
|
||||||
</Head>
|
</Head>
|
||||||
<WebSiteHeader
|
<WebSiteHeader projectName={'StocksageAI'} pages={pages} />
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
|
||||||
pages={pages}
|
|
||||||
/>
|
|
||||||
<main className={`flex-grow bg-white rounded-none `}>
|
<main className={`flex-grow bg-white rounded-none `}>
|
||||||
<HeroSection
|
<HeroSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
image={['AI analyzing stock charts']}
|
image={['AI analyzing stock charts']}
|
||||||
mainText={`Unlock Stock Potential with ${projectName}`}
|
mainText={`Unlock Stock Potential with ${projectName}`}
|
||||||
subTitle={`${projectName} leverages AI to analyze stocks in Nigeria and US markets, identifying undervalued opportunities for rapid growth. Discover your next investment today.`}
|
subTitle={`${projectName} leverages AI to analyze stocks in Nigeria and US markets, identifying undervalued opportunities for rapid growth. Discover your next investment today.`}
|
||||||
@ -150,9 +145,9 @@ export default function WebSite() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<FeaturesSection
|
<FeaturesSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
image={['AI-driven stock analysis']}
|
image={['AI-driven stock analysis']}
|
||||||
withBg={1}
|
withBg={0}
|
||||||
features={features_points}
|
features={features_points}
|
||||||
mainText={`Explore ${projectName} Features`}
|
mainText={`Explore ${projectName} Features`}
|
||||||
subTitle={`Discover how ${projectName} empowers investors with AI-driven insights and tools to make informed decisions.`}
|
subTitle={`Discover how ${projectName} empowers investors with AI-driven insights and tools to make informed decisions.`}
|
||||||
@ -160,14 +155,14 @@ export default function WebSite() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<PricingSection
|
<PricingSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
withBg={1}
|
withBg={1}
|
||||||
features={pricing_features}
|
features={pricing_features}
|
||||||
description={description}
|
description={description}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<AboutUsSection
|
<AboutUsSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
image={['Team collaborating on stock analysis']}
|
image={['Team collaborating on stock analysis']}
|
||||||
mainText={`Empowering Investors with ${projectName}`}
|
mainText={`Empowering Investors with ${projectName}`}
|
||||||
subTitle={`At ${projectName}, we harness the power of AI to provide investors with unparalleled insights into the stock market. Our mission is to simplify investment decisions and maximize growth potential.`}
|
subTitle={`At ${projectName}, we harness the power of AI to provide investors with unparalleled insights into the stock market. Our mission is to simplify investment decisions and maximize growth potential.`}
|
||||||
@ -175,10 +170,7 @@ export default function WebSite() {
|
|||||||
buttonText={`Learn More About Us`}
|
buttonText={`Learn More About Us`}
|
||||||
/>
|
/>
|
||||||
</main>
|
</main>
|
||||||
<WebSiteFooter
|
<WebSiteFooter projectName={'StocksageAI'} pages={pages} />
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
|
||||||
pages={pages}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,8 +18,10 @@ import { getPageTitle } from '../config';
|
|||||||
import { findMe, loginUser, resetAction } from '../stores/authSlice';
|
import { findMe, loginUser, resetAction } from '../stores/authSlice';
|
||||||
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import placeholderImage from '../assets/login-placeholder.jpg';
|
||||||
|
// Removed Pexels dependencies and will use a static placeholder image instead
|
||||||
|
|
||||||
import { toast, ToastContainer } from 'react-toastify';
|
import { toast, ToastContainer } from 'react-toastify';
|
||||||
import { getPexelsImage, getPexelsVideo } from '../helpers/pexels';
|
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
const { t } = useTranslation('common');
|
const { t } = useTranslation('common');
|
||||||
@ -52,18 +54,8 @@ export default function Login() {
|
|||||||
remember: true,
|
remember: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const title = 'Build SaaS app that analysis stock in Nigeria';
|
const title = 'StocksageAI';
|
||||||
|
|
||||||
// Fetch Pexels image/video
|
|
||||||
useEffect(() => {
|
|
||||||
async function fetchData() {
|
|
||||||
const image = await getPexelsImage();
|
|
||||||
const video = await getPexelsVideo();
|
|
||||||
setIllustrationImage(image);
|
|
||||||
setIllustrationVideo(video);
|
|
||||||
}
|
|
||||||
fetchData();
|
|
||||||
}, []);
|
|
||||||
// Fetch user data
|
// Fetch user data
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|||||||
320
frontend/src/pages/login.tsx.temp
Normal file
320
frontend/src/pages/login.tsx.temp
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import type { ReactElement } from 'react';
|
||||||
|
import Head from 'next/head';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import BaseButton from '../components/BaseButton';
|
||||||
|
import CardBox from '../components/CardBox';
|
||||||
|
import BaseIcon from '../components/BaseIcon';
|
||||||
|
import { mdiInformation, mdiEye, mdiEyeOff } from '@mdi/js';
|
||||||
|
import SectionFullScreen from '../components/SectionFullScreen';
|
||||||
|
import LayoutGuest from '../layouts/Guest';
|
||||||
|
import { Field, Form, Formik } from 'formik';
|
||||||
|
import FormField from '../components/FormField';
|
||||||
|
import FormCheckRadio from '../components/FormCheckRadio';
|
||||||
|
import BaseDivider from '../components/BaseDivider';
|
||||||
|
import BaseButtons from '../components/BaseButtons';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { getPageTitle } from '../config';
|
||||||
|
import { findMe, loginUser, resetAction } from '../stores/authSlice';
|
||||||
|
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import placeholderImage from '../assets/login-placeholder.jpg';
|
||||||
|
// Removed Pexels dependencies and will use a static placeholder image instead
|
||||||
|
|
||||||
|
import { toast, ToastContainer } from 'react-toastify';
|
||||||
|
|
||||||
|
export default function Login() {
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
const router = useRouter();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const textColor = useAppSelector((state) => state.style.linkColor);
|
||||||
|
const iconsColor = useAppSelector((state) => state.style.iconsColor);
|
||||||
|
const notify = (type, msg) => toast(msg, { type });
|
||||||
|
const [illustrationImage, setIllustrationImage] = useState({
|
||||||
|
src: undefined,
|
||||||
|
photographer: undefined,
|
||||||
|
photographer_url: undefined,
|
||||||
|
});
|
||||||
|
const [illustrationVideo, setIllustrationVideo] = useState({
|
||||||
|
video_files: [],
|
||||||
|
});
|
||||||
|
const [contentType, setContentType] = useState('video');
|
||||||
|
const [contentPosition, setContentPosition] = useState('left');
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
const {
|
||||||
|
currentUser,
|
||||||
|
isFetching,
|
||||||
|
errorMessage,
|
||||||
|
token,
|
||||||
|
notify: notifyState,
|
||||||
|
} = useAppSelector((state) => state.auth);
|
||||||
|
const [initialValues, setInitialValues] = React.useState({
|
||||||
|
email: 'super_admin@flatlogic.com',
|
||||||
|
password: '8ca3e282',
|
||||||
|
remember: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const title = 'StocksageAI';
|
||||||
|
|
||||||
|
// Fetch user data
|
||||||
|
useEffect(() => {
|
||||||
|
if (token) {
|
||||||
|
dispatch(findMe());
|
||||||
|
}
|
||||||
|
}, [token, dispatch]);
|
||||||
|
// Redirect to dashboard if user is logged in
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentUser?.id) {
|
||||||
|
router.push('/dashboard');
|
||||||
|
}
|
||||||
|
}, [currentUser?.id, router]);
|
||||||
|
// Show error message if there is one
|
||||||
|
useEffect(() => {
|
||||||
|
if (errorMessage) {
|
||||||
|
notify('error', errorMessage);
|
||||||
|
}
|
||||||
|
}, [errorMessage]);
|
||||||
|
// Show notification if there is one
|
||||||
|
useEffect(() => {
|
||||||
|
if (notifyState?.showNotification) {
|
||||||
|
notify('success', notifyState?.textNotification);
|
||||||
|
dispatch(resetAction());
|
||||||
|
}
|
||||||
|
}, [notifyState?.showNotification]);
|
||||||
|
|
||||||
|
const togglePasswordVisibility = () => {
|
||||||
|
setShowPassword(!showPassword);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async (value) => {
|
||||||
|
const { remember, ...rest } = value;
|
||||||
|
await dispatch(loginUser(rest));
|
||||||
|
};
|
||||||
|
|
||||||
|
const setLogin = (target: HTMLElement) => {
|
||||||
|
setInitialValues((prev) => ({
|
||||||
|
...prev,
|
||||||
|
email: target.innerText.trim(),
|
||||||
|
password: target.dataset.password ?? '',
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const imageBlock = (image) => (
|
||||||
|
<div
|
||||||
|
className='hidden md:flex flex-col justify-end relative flex-grow-0 flex-shrink-0 w-1/3'
|
||||||
|
style={{
|
||||||
|
backgroundImage: `${
|
||||||
|
image
|
||||||
|
? `url(${image.src?.original})`
|
||||||
|
: 'linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.5))'
|
||||||
|
}`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'left center',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundPosition: 'left center',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Head>
|
||||||
|
<title>
|
||||||
|
{getPageTitle(t('pages.login.pageTitle', { defaultValue: 'Login' }))}
|
||||||
|
</title>
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
<SectionFullScreen bg='violet'>
|
||||||
|
<div
|
||||||
|
className={`flex ${
|
||||||
|
contentPosition === 'right' ? 'flex-row-reverse' : 'flex-row'
|
||||||
|
} min-h-screen w-full`}
|
||||||
|
>
|
||||||
|
{contentType === 'image' && contentPosition !== 'background'
|
||||||
|
? imageBlock(illustrationImage)
|
||||||
|
: null}
|
||||||
|
{contentType === 'video' && contentPosition !== 'background'
|
||||||
|
? videoBlock(illustrationVideo)
|
||||||
|
: null}
|
||||||
|
<div className='flex items-center justify-center flex-col space-y-4 w-full lg:w-full'>
|
||||||
|
<CardBox id='loginRoles' className='w-full md:w-3/5 lg:w-2/3'>
|
||||||
|
<Link href={'/home'}>
|
||||||
|
<h2 className='text-4xl font-semibold my-4'> {title}</h2>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<div className='flex flex-row text-gray-500 justify-between'>
|
||||||
|
<div>
|
||||||
|
<p className='mb-2'>
|
||||||
|
Use{' '}
|
||||||
|
<code
|
||||||
|
className={`cursor-pointer ${textColor} `}
|
||||||
|
data-password='8ca3e282'
|
||||||
|
onClick={(e) => setLogin(e.target)}
|
||||||
|
>
|
||||||
|
super_admin@flatlogic.com
|
||||||
|
</code>
|
||||||
|
{' / '}
|
||||||
|
<code className={`${textColor}`}>8ca3e282</code>
|
||||||
|
{' / '}
|
||||||
|
to login as Super Admin
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p className='mb-2'>
|
||||||
|
Use{' '}
|
||||||
|
<code
|
||||||
|
className={`cursor-pointer ${textColor} `}
|
||||||
|
data-password='8ca3e282'
|
||||||
|
onClick={(e) => setLogin(e.target)}
|
||||||
|
>
|
||||||
|
admin@flatlogic.com
|
||||||
|
</code>
|
||||||
|
{' / '}
|
||||||
|
<code className={`${textColor}`}>8ca3e282</code>
|
||||||
|
{' / '}
|
||||||
|
to login as Admin
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Use{' '}
|
||||||
|
<code
|
||||||
|
className={`cursor-pointer ${textColor} `}
|
||||||
|
data-password='4ab6dd8858d8'
|
||||||
|
onClick={(e) => setLogin(e.target)}
|
||||||
|
>
|
||||||
|
client@hello.com
|
||||||
|
</code>
|
||||||
|
{' / '}
|
||||||
|
<code className={`${textColor}`}>4ab6dd8858d8</code>
|
||||||
|
{' / '}
|
||||||
|
to login as User
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<BaseIcon
|
||||||
|
className={`${iconsColor}`}
|
||||||
|
w='w-16'
|
||||||
|
h='h-16'
|
||||||
|
size={48}
|
||||||
|
path={mdiInformation}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardBox>
|
||||||
|
|
||||||
|
<CardBox className='w-full md:w-3/5 lg:w-2/3'>
|
||||||
|
<Formik
|
||||||
|
initialValues={initialValues}
|
||||||
|
enableReinitialize
|
||||||
|
onSubmit={(values) => handleSubmit(values)}
|
||||||
|
>
|
||||||
|
<Form>
|
||||||
|
<FormField
|
||||||
|
label={t('pages.login.form.loginLabel', {
|
||||||
|
defaultValue: 'Login',
|
||||||
|
})}
|
||||||
|
help={t('pages.login.form.loginHelp', {
|
||||||
|
defaultValue: 'Please enter your login',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Field name='email' />
|
||||||
|
</FormField>
|
||||||
|
|
||||||
|
<div className='relative'>
|
||||||
|
<FormField
|
||||||
|
label={t('pages.login.form.passwordLabel', {
|
||||||
|
defaultValue: 'Password',
|
||||||
|
})}
|
||||||
|
help={t('pages.login.form.passwordHelp', {
|
||||||
|
defaultValue: 'Please enter your password',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Field
|
||||||
|
name='password'
|
||||||
|
type={showPassword ? 'text' : 'password'}
|
||||||
|
/>
|
||||||
|
</FormField>
|
||||||
|
<div
|
||||||
|
className='absolute bottom-8 right-0 pr-3 flex items-center cursor-pointer'
|
||||||
|
onClick={togglePasswordVisibility}
|
||||||
|
>
|
||||||
|
<BaseIcon
|
||||||
|
className='text-gray-500 hover:text-gray-700'
|
||||||
|
size={20}
|
||||||
|
path={showPassword ? mdiEyeOff : mdiEye}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={'flex justify-between'}>
|
||||||
|
<FormCheckRadio
|
||||||
|
type='checkbox'
|
||||||
|
label={t('pages.login.form.remember', {
|
||||||
|
defaultValue: 'Remember',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Field type='checkbox' name='remember' />
|
||||||
|
</FormCheckRadio>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
className={`${textColor} text-blue-600`}
|
||||||
|
href={'/forgot'}
|
||||||
|
>
|
||||||
|
{t('pages.login.form.forgotPassword', {
|
||||||
|
defaultValue: 'Forgot password?',
|
||||||
|
})}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<BaseDivider />
|
||||||
|
|
||||||
|
<BaseButtons>
|
||||||
|
<BaseButton
|
||||||
|
className={'w-full'}
|
||||||
|
type='submit'
|
||||||
|
label={
|
||||||
|
isFetching
|
||||||
|
? t('pages.login.form.loading', {
|
||||||
|
defaultValue: 'Loading...',
|
||||||
|
})
|
||||||
|
: t('pages.login.form.loginButton', {
|
||||||
|
defaultValue: 'Login',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
color='info'
|
||||||
|
disabled={isFetching}
|
||||||
|
/>
|
||||||
|
</BaseButtons>
|
||||||
|
<br />
|
||||||
|
<p className={'text-center'}>
|
||||||
|
{t('pages.login.form.noAccountYet', {
|
||||||
|
defaultValue: 'Don’t have an account yet?',
|
||||||
|
})}{' '}
|
||||||
|
<Link className={`${textColor}`} href={'/register'}>
|
||||||
|
{t('pages.login.form.newAccount', {
|
||||||
|
defaultValue: 'New Account',
|
||||||
|
})}
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
</Form>
|
||||||
|
</Formik>
|
||||||
|
</CardBox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SectionFullScreen>
|
||||||
|
<div className='bg-black text-white flex flex-col text-center justify-center md:flex-row'>
|
||||||
|
<p className='py-6 text-sm'>
|
||||||
|
© 2024 <span>{title}</span>.{' '}
|
||||||
|
{t('pages.login.footer.copyright', {
|
||||||
|
defaultValue: '© All rights reserved',
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
<Link className='py-6 ml-4 text-sm' href='/privacy-policy/'>
|
||||||
|
{t('pages.login.footer.privacy', { defaultValue: 'Privacy Policy' })}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<ToastContainer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Login.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
return <LayoutGuest>{page}</LayoutGuest>;
|
||||||
|
};
|
||||||
@ -5,7 +5,7 @@ import LayoutGuest from '../layouts/Guest';
|
|||||||
import { getPageTitle } from '../config';
|
import { getPageTitle } from '../config';
|
||||||
|
|
||||||
export default function PrivacyPolicy() {
|
export default function PrivacyPolicy() {
|
||||||
const title = 'Build SaaS app that analysis stock in Nigeria';
|
const title = 'StocksageAI';
|
||||||
const [projectUrl, setProjectUrl] = useState('');
|
const [projectUrl, setProjectUrl] = useState('');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { ReactElement, useEffect } from 'react';
|
import React, { ReactElement, useEffect, useState } from 'react';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import DatePicker from 'react-datepicker';
|
import DatePicker from 'react-datepicker';
|
||||||
import 'react-datepicker/dist/react-datepicker.css';
|
import 'react-datepicker/dist/react-datepicker.css';
|
||||||
@ -17,6 +17,21 @@ import CardBox from '../../components/CardBox';
|
|||||||
import BaseButton from '../../components/BaseButton';
|
import BaseButton from '../../components/BaseButton';
|
||||||
import BaseDivider from '../../components/BaseDivider';
|
import BaseDivider from '../../components/BaseDivider';
|
||||||
import { mdiChartTimelineVariant } from '@mdi/js';
|
import { mdiChartTimelineVariant } from '@mdi/js';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import { Line } from 'react-chartjs-2';
|
||||||
|
import {
|
||||||
|
Chart as ChartJS,
|
||||||
|
LineElement,
|
||||||
|
PointElement,
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
} from 'chart.js';
|
||||||
|
|
||||||
|
ChartJS.register(LineElement, PointElement, CategoryScale, LinearScale, Tooltip, Legend);
|
||||||
|
|
||||||
import { SwitchField } from '../../components/SwitchField';
|
import { SwitchField } from '../../components/SwitchField';
|
||||||
import FormField from '../../components/FormField';
|
import FormField from '../../components/FormField';
|
||||||
|
|
||||||
@ -34,6 +49,33 @@ const StocksView = () => {
|
|||||||
function removeLastCharacter(str) {
|
function removeLastCharacter(str) {
|
||||||
console.log(str, `str`);
|
console.log(str, `str`);
|
||||||
return str.slice(0, -1);
|
return str.slice(0, -1);
|
||||||
|
|
||||||
|
// Chart timeframe controls and data state
|
||||||
|
const ranges = ['daily','weekly','monthly','3m','6m','1y','3y','5y'];
|
||||||
|
const [selectedRange, setSelectedRange] = useState('monthly');
|
||||||
|
const [chartData, setChartData] = useState([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!id) return;
|
||||||
|
axios.get(`/api/stocks/${id}/price-history?range=${selectedRange}`)
|
||||||
|
.then(res => setChartData(res.data))
|
||||||
|
.catch(err => console.error(err));
|
||||||
|
}, [id, selectedRange]);
|
||||||
|
|
||||||
|
// Prepare data for Chart.js
|
||||||
|
const chartLabels = chartData.map(item => dayjs(item.date).format('YYYY-MM-DD'));
|
||||||
|
const chartPrices = chartData.map(item => item.price);
|
||||||
|
const chartJsData = {
|
||||||
|
labels: chartLabels,
|
||||||
|
datasets: [{
|
||||||
|
label: `Price (${selectedRange})`,
|
||||||
|
data: chartPrices,
|
||||||
|
borderColor: '#4F46E5',
|
||||||
|
backgroundColor: 'rgba(79,70,229,0.5)',
|
||||||
|
fill: false,
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -43,6 +85,27 @@ const StocksView = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
|
<div className="mb-4">
|
||||||
|
<div className="flex space-x-2 mb-4">
|
||||||
|
{ranges.map(range => (
|
||||||
|
<button
|
||||||
|
key={range}
|
||||||
|
onClick={() => setSelectedRange(range)}
|
||||||
|
className={
|
||||||
|
selectedRange === range
|
||||||
|
? 'px-3 py-1 rounded border bg-blue-500 text-white'
|
||||||
|
: 'px-3 py-1 rounded border bg-white text-blue-500'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{range.toUpperCase()}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="h-64 mb-4">
|
||||||
|
<Line data={chartJsData} options={{ responsive: true, maintainAspectRatio: false }} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<title>{getPageTitle('View stocks')}</title>
|
<title>{getPageTitle('View stocks')}</title>
|
||||||
</Head>
|
</Head>
|
||||||
<SectionMain>
|
<SectionMain>
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import LayoutGuest from '../layouts/Guest';
|
|||||||
import { getPageTitle } from '../config';
|
import { getPageTitle } from '../config';
|
||||||
|
|
||||||
export default function PrivacyPolicy() {
|
export default function PrivacyPolicy() {
|
||||||
const title = 'Build SaaS app that analysis stock in Nigeria';
|
const title = 'StocksageAI';
|
||||||
const [projectUrl, setProjectUrl] = useState('');
|
const [projectUrl, setProjectUrl] = useState('');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import FaqSection from '../../components/WebPageComponents/FaqComponent';
|
|||||||
export default function WebSite() {
|
export default function WebSite() {
|
||||||
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
||||||
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
||||||
const projectName = 'Build SaaS app that analysis stock in Nigeria';
|
const projectName = 'StocksageAI';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const darkElement = document.querySelector('body .dark');
|
const darkElement = document.querySelector('body .dark');
|
||||||
@ -67,17 +67,15 @@ export default function WebSite() {
|
|||||||
<div className='flex flex-col min-h-screen'>
|
<div className='flex flex-col min-h-screen'>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{`Contact StockSageAI Support`}</title>
|
<title>{`Contact StockSageAI Support`}</title>
|
||||||
<meta
|
<title>{`Contact StocksageAI Support`}</title>
|
||||||
name='description'
|
name='description'
|
||||||
content={`Get in touch with StockSageAI for any inquiries, support, or feedback. Our team is here to assist you with your stock analysis needs.`}
|
content={`Get in touch with StockSageAI for any inquiries, support, or feedback. Our team is here to assist you with your stock analysis needs.`}
|
||||||
/>
|
content={`Get in touch with StocksageAI for any inquiries, support, or feedback. Our team is here to assist you with your stock analysis needs.`}
|
||||||
</Head>
|
</Head>
|
||||||
<WebSiteHeader
|
<WebSiteHeader projectName={'StocksageAI'} />
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
|
||||||
/>
|
|
||||||
<main className={`flex-grow bg-white rounded-none `}>
|
<main className={`flex-grow bg-white rounded-none `}>
|
||||||
<HeroSection
|
<HeroSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
image={['Customer support team ready']}
|
image={['Customer support team ready']}
|
||||||
mainText={`Connect with ${projectName} Support Team`}
|
mainText={`Connect with ${projectName} Support Team`}
|
||||||
subTitle={`Have questions or need assistance? Our dedicated support team at ${projectName} is here to help you with any inquiries or feedback. Reach out to us today.`}
|
subTitle={`Have questions or need assistance? Our dedicated support team at ${projectName} is here to help you with any inquiries or feedback. Reach out to us today.`}
|
||||||
@ -86,23 +84,21 @@ export default function WebSite() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<FaqSection
|
<FaqSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
design={FaqDesigns.TWO_COLUMN || ''}
|
design={FaqDesigns.TWO_COLUMN || ''}
|
||||||
faqs={faqs}
|
faqs={faqs}
|
||||||
mainText={`${projectName} Support FAQs `}
|
mainText={`${projectName} Support FAQs `}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ContactFormSection
|
<ContactFormSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
design={ContactFormDesigns.WITH_IMAGE || ''}
|
design={ContactFormDesigns.WITH_IMAGE || ''}
|
||||||
image={['Email communication illustration']}
|
image={['Email communication illustration']}
|
||||||
mainText={`Reach Out to ${projectName} `}
|
mainText={`Reach Out to ${projectName} `}
|
||||||
subTitle={`We're here to assist you. Contact us anytime, and our team will respond promptly to your inquiries. Your feedback is valuable to us at ${projectName}.`}
|
subTitle={`We're here to assist you. Contact us anytime, and our team will respond promptly to your inquiries. Your feedback is valuable to us at ${projectName}.`}
|
||||||
/>
|
/>
|
||||||
</main>
|
</main>
|
||||||
<WebSiteFooter
|
<WebSiteFooter projectName={'StocksageAI'} />
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import AboutUsSection from '../../components/WebPageComponents/AboutUsComponent'
|
|||||||
export default function WebSite() {
|
export default function WebSite() {
|
||||||
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
||||||
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
||||||
const projectName = 'Build SaaS app that analysis stock in Nigeria';
|
const projectName = 'StocksageAI';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const darkElement = document.querySelector('body .dark');
|
const darkElement = document.querySelector('body .dark');
|
||||||
@ -114,17 +114,14 @@ export default function WebSite() {
|
|||||||
<div className='flex flex-col min-h-screen'>
|
<div className='flex flex-col min-h-screen'>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{`StockSageAI - Discover Undervalued Stocks with AI Insights`}</title>
|
<title>{`StockSageAI - Discover Undervalued Stocks with AI Insights`}</title>
|
||||||
<meta
|
<title>{`StocksageAI - Discover Undervalued Stocks with AI Insights`}</title>
|
||||||
name='description'
|
|
||||||
content={`Explore StockSageAI, the AI-powered platform that analyzes stocks in Nigeria and US markets using fundamental, technical, and sentiment data to identify undervalued stocks poised for growth.`}
|
content={`Explore StockSageAI, the AI-powered platform that analyzes stocks in Nigeria and US markets using fundamental, technical, and sentiment data to identify undervalued stocks poised for growth.`}
|
||||||
/>
|
content={`Explore StocksageAI, the AI-powered platform that analyzes stocks in Nigeria and US markets using fundamental, technical, and sentiment data to identify undervalued stocks poised for growth.`}
|
||||||
</Head>
|
</Head>
|
||||||
<WebSiteHeader
|
<WebSiteHeader projectName={'StocksageAI'} />
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
|
||||||
/>
|
|
||||||
<main className={`flex-grow bg-white rounded-none `}>
|
<main className={`flex-grow bg-white rounded-none `}>
|
||||||
<HeroSection
|
<HeroSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
image={['AI analyzing stock charts']}
|
image={['AI analyzing stock charts']}
|
||||||
mainText={`Unlock Stock Potential with ${projectName}`}
|
mainText={`Unlock Stock Potential with ${projectName}`}
|
||||||
subTitle={`${projectName} leverages AI to analyze stocks in Nigeria and US markets, identifying undervalued opportunities for rapid growth. Discover your next investment today.`}
|
subTitle={`${projectName} leverages AI to analyze stocks in Nigeria and US markets, identifying undervalued opportunities for rapid growth. Discover your next investment today.`}
|
||||||
@ -133,9 +130,9 @@ export default function WebSite() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<FeaturesSection
|
<FeaturesSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
image={['AI-driven stock analysis']}
|
image={['AI-driven stock analysis']}
|
||||||
withBg={0}
|
withBg={1}
|
||||||
features={features_points}
|
features={features_points}
|
||||||
mainText={`Explore ${projectName} Features`}
|
mainText={`Explore ${projectName} Features`}
|
||||||
subTitle={`Discover how ${projectName} empowers investors with AI-driven insights and tools to make informed decisions.`}
|
subTitle={`Discover how ${projectName} empowers investors with AI-driven insights and tools to make informed decisions.`}
|
||||||
@ -143,14 +140,14 @@ export default function WebSite() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<PricingSection
|
<PricingSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
withBg={0}
|
withBg={0}
|
||||||
features={pricing_features}
|
features={pricing_features}
|
||||||
description={description}
|
description={description}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<AboutUsSection
|
<AboutUsSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
image={['Team collaborating on stock analysis']}
|
image={['Team collaborating on stock analysis']}
|
||||||
mainText={`Empowering Investors with ${projectName}`}
|
mainText={`Empowering Investors with ${projectName}`}
|
||||||
subTitle={`At ${projectName}, we harness the power of AI to provide investors with unparalleled insights into the stock market. Our mission is to simplify investment decisions and maximize growth potential.`}
|
subTitle={`At ${projectName}, we harness the power of AI to provide investors with unparalleled insights into the stock market. Our mission is to simplify investment decisions and maximize growth potential.`}
|
||||||
@ -158,9 +155,7 @@ export default function WebSite() {
|
|||||||
buttonText={`Learn More About Us`}
|
buttonText={`Learn More About Us`}
|
||||||
/>
|
/>
|
||||||
</main>
|
</main>
|
||||||
<WebSiteFooter
|
<WebSiteFooter projectName={'StocksageAI'} />
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import FaqSection from '../../components/WebPageComponents/FaqComponent';
|
|||||||
export default function WebSite() {
|
export default function WebSite() {
|
||||||
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
||||||
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
||||||
const projectName = 'Build SaaS app that analysis stock in Nigeria';
|
const projectName = 'StocksageAI';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const darkElement = document.querySelector('body .dark');
|
const darkElement = document.querySelector('body .dark');
|
||||||
@ -111,17 +111,15 @@ export default function WebSite() {
|
|||||||
<div className='flex flex-col min-h-screen'>
|
<div className='flex flex-col min-h-screen'>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{`StockSageAI Pricing Plans`}</title>
|
<title>{`StockSageAI Pricing Plans`}</title>
|
||||||
<meta
|
<title>{`StocksageAI Pricing Plans`}</title>
|
||||||
name='description'
|
name='description'
|
||||||
content={`Explore the flexible pricing plans of StockSageAI, designed to cater to individual investors, small businesses, and enterprises with AI-driven stock insights.`}
|
content={`Explore the flexible pricing plans of StockSageAI, designed to cater to individual investors, small businesses, and enterprises with AI-driven stock insights.`}
|
||||||
/>
|
content={`Explore the flexible pricing plans of StocksageAI, designed to cater to individual investors, small businesses, and enterprises with AI-driven stock insights.`}
|
||||||
</Head>
|
</Head>
|
||||||
<WebSiteHeader
|
<WebSiteHeader projectName={'StocksageAI'} />
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
|
||||||
/>
|
|
||||||
<main className={`flex-grow bg-white rounded-none `}>
|
<main className={`flex-grow bg-white rounded-none `}>
|
||||||
<HeroSection
|
<HeroSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
image={['Diverse pricing plans illustration']}
|
image={['Diverse pricing plans illustration']}
|
||||||
mainText={`Choose Your ${projectName} Plan Today`}
|
mainText={`Choose Your ${projectName} Plan Today`}
|
||||||
subTitle={`Discover flexible pricing options with ${projectName} tailored to meet the needs of individual investors, startups, and enterprises. Unlock the power of AI-driven stock insights.`}
|
subTitle={`Discover flexible pricing options with ${projectName} tailored to meet the needs of individual investors, startups, and enterprises. Unlock the power of AI-driven stock insights.`}
|
||||||
@ -130,22 +128,20 @@ export default function WebSite() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<PricingSection
|
<PricingSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
withBg={0}
|
withBg={1}
|
||||||
features={pricing_features}
|
features={pricing_features}
|
||||||
description={description}
|
description={description}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FaqSection
|
<FaqSection
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
projectName={'StocksageAI'}
|
||||||
design={FaqDesigns.ACCORDION || ''}
|
design={FaqDesigns.ACCORDION || ''}
|
||||||
faqs={faqs}
|
faqs={faqs}
|
||||||
mainText={`${projectName} Frequently Asked Questions `}
|
mainText={`${projectName} Frequently Asked Questions `}
|
||||||
/>
|
/>
|
||||||
</main>
|
</main>
|
||||||
<WebSiteFooter
|
<WebSiteFooter projectName={'StocksageAI'} />
|
||||||
projectName={'Build SaaS app that analysis stock in Nigeria'}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user