mirror of
https://github.com/wasp-lang/open-saas.git
synced 2025-04-11 13:29:13 +02:00
add landing page features & fix gpt response
This commit is contained in:
parent
4e56986977
commit
c1b99c6e55
@ -1,3 +1,4 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { User } from '@wasp/entities';
|
||||
import { useQuery } from '@wasp/queries';
|
||||
import getGptResponses from '@wasp/queries/getGptResponses';
|
||||
@ -7,8 +8,14 @@ import { STRIPE_CUSTOMER_PORTAL_LINK } from '@wasp/shared/constants';
|
||||
import { TierIds } from '@wasp/shared/constants';
|
||||
|
||||
export default function AccountPage({ user }: { user: User }) {
|
||||
const [ lastGptResponse, setLastGptResponse ] = useState<string[]>([]);
|
||||
const { data: gptResponses, isLoading: isLoadingGptResponses } = useQuery(getGptResponses);
|
||||
|
||||
useEffect(() => {
|
||||
if (gptResponses && gptResponses.length > 0) {
|
||||
setLastGptResponse(gptResponses[gptResponses.length - 1].content.split('\n'));
|
||||
}
|
||||
}, [gptResponses]);
|
||||
return (
|
||||
<div className='mt-10 px-6'>
|
||||
<div className='overflow-hidden bg-white ring-1 ring-gray-900/10 shadow-lg sm:rounded-lg lg:m-8 '>
|
||||
@ -51,11 +58,10 @@ export default function AccountPage({ user }: { user: User }) {
|
||||
</div>
|
||||
<div className='py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-5 sm:px-6'>
|
||||
<dt className='text-sm font-medium text-gray-500'>Most Recent GPT Response</dt>
|
||||
<dd className='mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0'>
|
||||
<dd className='flex flex-col gap-2 mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0'>
|
||||
{isLoadingGptResponses
|
||||
? 'Loading...'
|
||||
: !!gptResponses && gptResponses.length > 0
|
||||
? gptResponses[gptResponses.length - 1].content
|
||||
: lastGptResponse.length > 0 ? lastGptResponse.map((str) => <p key={str}>{str}</p>)
|
||||
: "You don't have any at this time."}
|
||||
</dd>
|
||||
</div>
|
||||
|
@ -5,7 +5,7 @@ import useAuth from '@wasp/auth/useAuth';
|
||||
|
||||
export default function GptPage() {
|
||||
const [temperature, setTemperature] = useState<number>(1);
|
||||
const [response, setResponse] = useState<string>('');
|
||||
const [response, setResponse] = useState<string[]>([]);
|
||||
|
||||
const { data: user } = useAuth();
|
||||
|
||||
@ -18,11 +18,12 @@ export default function GptPage() {
|
||||
try {
|
||||
const response = await generateGptResponse({ instructions, command, temperature });
|
||||
if (response) {
|
||||
setResponse(response.content);
|
||||
setResponse(response.split('\n'));
|
||||
console.log(response)
|
||||
}
|
||||
} catch (e) {
|
||||
alert('Something went wrong. Please try again.');
|
||||
console.error(e);
|
||||
} catch (error: any) {
|
||||
alert(error.message);
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
@ -124,7 +125,7 @@ export default function GptPage() {
|
||||
<button
|
||||
type='submit'
|
||||
className={`${
|
||||
isSubmitting && 'animate-puls'
|
||||
isSubmitting && 'opacity-70 cursor-wait'
|
||||
} rounded-md bg-yellow-500 py-2 px-3 text-sm font-semibold text-white shadow-sm hover:bg-yellow-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600`}
|
||||
>
|
||||
{!isSubmitting ? 'Submit' : 'Loading...'}
|
||||
@ -134,10 +135,10 @@ export default function GptPage() {
|
||||
<div
|
||||
className={`${
|
||||
isSubmitting && 'animate-pulse'
|
||||
} mt-2 mx-6 flex justify-center rounded-lg border border-dashed border-gray-900/25 mt-10 sm:w-[90%] md:w-[50%] mx-auto mt-12 px-6 py-10`}
|
||||
} mt-4 mx-6 flex justify-center rounded-lg border border-dashed border-gray-900/25 sm:w-[90%] md:w-[50%] mx-auto mt-12 px-6 py-10`}
|
||||
>
|
||||
<div className='space-y-2 text-center'>
|
||||
<p className='text-sm text-gray-500'>{response ? response : 'GPT Response will load here'}</p>
|
||||
<div className='space-y-2 flex flex-col gap-2 text-center text-sm text-gray-500 w-full'>
|
||||
{response.length > 0 ? response.map((str) => <p key={str}>{str}</p>) : <p>GPT Response will load here</p>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -217,7 +217,7 @@ export default function LandingPage() {
|
||||
<div className='mt-12 mx-auto max-w-7xl px-6 lg:px-8 flex flex-col items-between gap-y-6'>
|
||||
<h2 className='mb-6 text-center font-semibold tracking-wide text-gray-500'>Built and Ships with</h2>
|
||||
|
||||
<div className='mx-auto grid max-w-lg grid-cols-2 items-center gap-x-8 gap-y-12 sm:max-w-xl md:grid-cols-6 sm:gap-x-10 sm:gap-y-14 lg:mx-0 lg:max-w-none'>
|
||||
<div className='mx-auto grid max-w-lg grid-cols-2 items-center gap-x-8 gap-y-12 sm:max-w-xl md:grid-cols-4 sm:gap-x-10 sm:gap-y-14 lg:mx-0 lg:max-w-none'>
|
||||
<img
|
||||
className=' col-span-1 max-h-12 w-full object-contain grayscale opacity-100'
|
||||
src='https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/512px-React-icon.svg.png'
|
||||
@ -225,7 +225,7 @@ export default function LandingPage() {
|
||||
height={48}
|
||||
/>
|
||||
<img
|
||||
className=' col-span-1 max-h-12 w-full object-contain grayscale opacity-70 '
|
||||
className=' col-span-1 max-h-12 w-full object-contain grayscale opacity-60 '
|
||||
src='https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Node.js_logo.svg/590px-Node.js_logo.svg.png'
|
||||
alt='NodeJS'
|
||||
height={48}
|
||||
@ -238,7 +238,6 @@ export default function LandingPage() {
|
||||
/>
|
||||
<div className='flex justify-center col-span-1 max-h-12 w-full object-contain grayscale opacity-80'>
|
||||
<svg width={48} height={48} viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'>
|
||||
<title>file_type_prisma</title>
|
||||
<path
|
||||
fill='#545454'
|
||||
d='M25.21,24.21,12.739,27.928a.525.525,0,0,1-.667-.606L16.528,5.811a.43.43,0,0,1,.809-.094l8.249,17.661A.6.6,0,0,1,25.21,24.21Zm2.139-.878L17.8,2.883h0A1.531,1.531,0,0,0,16.491,2a1.513,1.513,0,0,0-1.4.729L4.736,19.648a1.592,1.592,0,0,0,.018,1.7l5.064,7.909a1.628,1.628,0,0,0,1.83.678l14.7-4.383a1.6,1.6,0,0,0,1-2.218Z'
|
||||
@ -257,6 +256,30 @@ export default function LandingPage() {
|
||||
alt='Stripe'
|
||||
height={48}
|
||||
/>
|
||||
<div className='flex justify-center col-span-1 w-full max-h-12 object-contain grayscale opacity-75'>
|
||||
<svg viewBox='0 0 256 370' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
fill='#545454'
|
||||
d='M182.022 9.147c2.982 3.702 4.502 8.697 7.543 18.687L256 246.074a276.467 276.467 0 0 0-79.426-26.891L133.318 73.008a5.63 5.63 0 0 0-10.802.017L79.784 219.11A276.453 276.453 0 0 0 0 246.04L66.76 27.783c3.051-9.972 4.577-14.959 7.559-18.654a24.541 24.541 0 0 1 9.946-7.358C88.67 0 93.885 0 104.314 0h47.683c10.443 0 15.664 0 20.074 1.774a24.545 24.545 0 0 1 9.95 7.373Z'
|
||||
/>
|
||||
<path
|
||||
fill='#545454'
|
||||
d='M189.972 256.46c-10.952 9.364-32.812 15.751-57.992 15.751-30.904 0-56.807-9.621-63.68-22.56-2.458 7.415-3.009 15.903-3.009 21.324 0 0-1.619 26.623 16.898 45.14 0-9.615 7.795-17.41 17.41-17.41 16.48 0 16.46 14.378 16.446 26.043l-.001 1.041c0 17.705 10.82 32.883 26.21 39.28a35.685 35.685 0 0 1-3.588-15.647c0-16.886 9.913-23.173 21.435-30.48 9.167-5.814 19.353-12.274 26.372-25.232a47.588 47.588 0 0 0 5.742-22.735c0-5.06-.786-9.938-2.243-14.516Z'
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className='flex justify-center col-span-1 w-full max-h-12 object-contain grayscale opacity-75'>
|
||||
<svg
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
preserveAspectRatio='xMidYMid'
|
||||
viewBox='0 0 256 260'
|
||||
>
|
||||
<path
|
||||
fill='#545454'
|
||||
d='M239.184 106.203a64.716 64.716 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.716 64.716 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.665 64.665 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.767 64.767 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483Zm-97.56 136.338a48.397 48.397 0 0 1-31.105-11.255l1.535-.87 51.67-29.825a8.595 8.595 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601Zm-104.466-44.61a48.345 48.345 0 0 1-5.781-32.589l1.534.921 51.722 29.826a8.339 8.339 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803ZM23.549 85.38a48.499 48.499 0 0 1 25.58-21.333v61.39a8.288 8.288 0 0 0 4.195 7.316l62.874 36.272-21.845 12.636a.819.819 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405v.256Zm179.466 41.695-63.08-36.63L161.73 77.86a.819.819 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.544 8.544 0 0 0-4.4-7.213Zm21.742-32.69-1.535-.922-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.716.716 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391v.205ZM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87-51.67 29.825a8.595 8.595 0 0 0-4.246 7.367l-.051 72.697Zm11.868-25.58 28.138-16.217 28.188 16.218v32.434l-28.086 16.218-28.188-16.218-.052-32.434Z'
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -274,8 +297,8 @@ export default function LandingPage() {
|
||||
</div>
|
||||
<div className='mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-24 lg:max-w-4xl'>
|
||||
<dl className='grid max-w-xl grid-cols-1 gap-x-8 gap-y-10 lg:max-w-none lg:grid-cols-2 lg:gap-y-16'>
|
||||
{features.map((feature, idx) => (
|
||||
<div key={feature.name} className={`relative pl-16 ${idx === features.length - 1 ? `mx-auto lg:col-span-2 lg:w-1/2` : ''}`}>
|
||||
{features.map((feature) => (
|
||||
<div key={feature.name} className={`relative pl-16`}>
|
||||
<dt className='text-base font-semibold leading-7 text-gray-900'>
|
||||
<div className='absolute left-0 top-0 flex h-10 w-10 items-center justify-center border border-yellow-400 bg-yellow-100/50 rounded-lg'>
|
||||
<div className='text-2xl'>{feature.icon}</div>
|
||||
@ -297,24 +320,19 @@ export default function LandingPage() {
|
||||
<div className='relative flex flex-wrap gap-6 w-full mt-6 z-10 justify-between lg:mx-0'>
|
||||
{testimonials.map((testimonial) => (
|
||||
<figure className='w-full lg:w-1/4 box-content flex flex-col justify-between p-8 rounded-xl bg-gray-500/5 '>
|
||||
<blockquote className='text-lg text-white sm:text-md sm:leading-8'>
|
||||
<p>
|
||||
{testimonial.quote}
|
||||
</p>
|
||||
</blockquote>
|
||||
<figcaption className='mt-6 text-base text-white'>
|
||||
<a href={testimonial.socialUrl} className='flex items-center gap-x-2'>
|
||||
<img
|
||||
src={testimonial.avatarSrc}
|
||||
className='h-12 w-12 rounded-full'
|
||||
/>
|
||||
<div>
|
||||
<div className='font-semibold hover:underline'>{testimonial.name}</div>
|
||||
<div className='mt-1'>{testimonial.role}</div>
|
||||
</div>
|
||||
</a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
<blockquote className='text-lg text-white sm:text-md sm:leading-8'>
|
||||
<p>{testimonial.quote}</p>
|
||||
</blockquote>
|
||||
<figcaption className='mt-6 text-base text-white'>
|
||||
<a href={testimonial.socialUrl} className='flex items-center gap-x-2'>
|
||||
<img src={testimonial.avatarSrc} className='h-12 w-12 rounded-full' />
|
||||
<div>
|
||||
<div className='font-semibold hover:underline'>{testimonial.name}</div>
|
||||
<div className='mt-1'>{testimonial.role}</div>
|
||||
</div>
|
||||
</a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -36,6 +36,11 @@ export const features = [
|
||||
description: 'Graphs! Tables! Analytics w/ Plausible or Google! All in one place. Ooooooooooh.',
|
||||
icon: '📈',
|
||||
},
|
||||
{
|
||||
name: 'Blog w/ Astro',
|
||||
description: 'Built-in blog with the Astro framework. Write your posts in Markdown, and watch your SEO performance take off.',
|
||||
icon: '📝',
|
||||
},
|
||||
{
|
||||
name: 'Email Sending',
|
||||
description:
|
||||
|
@ -56,7 +56,7 @@ type GptPayload = {
|
||||
temperature: number;
|
||||
};
|
||||
|
||||
export const generateGptResponse: GenerateGptResponse<GptPayload, GptResponse> = async (
|
||||
export const generateGptResponse: GenerateGptResponse<GptPayload, string> = async (
|
||||
{ instructions, command, temperature },
|
||||
context
|
||||
) => {
|
||||
@ -105,13 +105,17 @@ export const generateGptResponse: GenerateGptResponse<GptPayload, GptResponse> =
|
||||
});
|
||||
|
||||
const json = (await response.json()) as OpenAIResponse;
|
||||
console.log('response json', json);
|
||||
return context.entities.GptResponse.create({
|
||||
console.log('response json', json?.choices[0].message.content);
|
||||
if (!json?.choices[0].message.content) {
|
||||
throw new HttpError(500, 'No response from OpenAI');
|
||||
}
|
||||
await context.entities.GptResponse.create({
|
||||
data: {
|
||||
content: json?.choices[0].message.content,
|
||||
user: { connect: { id: context.user.id } },
|
||||
},
|
||||
});
|
||||
return json?.choices[0].message.content;
|
||||
} catch (error: any) {
|
||||
if (!context.user.hasPaid && error?.statusCode != 402) {
|
||||
await context.entities.User.update({
|
||||
|
Loading…
x
Reference in New Issue
Block a user