Properties "missing" from type definitions for schemas for Sanity - json

I'm using Sanity in a project and came across an error when I tried to pass props to a component
that says: "Type 'Card[]' is missing the following properties from type 'Card': _type, title, image, description, and 4 more." Card in this context is one of my schemas for Sanity that I created. When I run my web app, I also get: "SyntaxError: Unexpected token < in JSON at position 0" I'm trying to figure out why my fetching data won't work.
I've checked my type definition file, my fetch functions etc to make sure that everything connected correctly and and I didn't have any spelling or importing errors. I've also tried restarting my server. At the bottom of my index page, i'm using a getStaticProps async function. When I comment it out, my app runs, so the problem has something to do with that.
my code:
Index:
import type { GetStaticProps} from 'next';
import Head from 'next/head'
import Image from 'next/image'
import React from 'react'
import Header from 'components/Header'
import Hero from 'components/Hero'
import Middle from 'components/Middle'
import Chapters from 'components/Chapters'
import Footer from 'components/Footer'
import {Card, CardList, Chapter, Banner, Pages, Summary, SlideCard} from "typings"
import { fetchCard} from 'utils/fetchCard'
import { fetchCardList} from 'utils/fetchCardList'
import {fetchChapter} from 'utils/fetchChapter'
import {fetchBanner} from 'utils/fetchBanner'
import { fetchPages} from 'utils/fetchPages'
import { fetchSummary} from 'utils/fetchSummary'
import { fetchSlideCard} from 'utils/fetchSlideCard'
type Props = {
card: Card[];
cardList: CardList[];
chapter: Chapter[];
banner: Banner[];
pages: Pages[];
summary: Summary[];
slideCard: SlideCard[];
}
export default function Home({card, cardList, chapter, banner, pages, summary, slideCard}: Props ) {
return (
<>
<Head>
<title>Shonen Jump Plus 2</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="max-w-screen-2xl mx-auto">
<div>
<Header />
<Hero card={card}/>
<Middle />
<Chapters />
<Footer />
{/* Hero Slides */}
{/* Four Featured */}
{/* Latest Chapters */}
</div>
</main>
</>
)
}
export const getStaticProps: GetStaticProps<Props> = async () => {
const card: Card[] = await fetchCard();
const cardList: CardList[] = await fetchCardList();
const chapter: Chapter[] = await fetchChapter();
const banner: Banner[] = await fetchBanner();
const pages: Pages[] = await fetchPages();
const slideCard: SlideCard[] = await fetchSlideCard();
const summary: Summary[] = await fetchSummary();
return {
props: {
card,
cardList,
chapter,
banner,
pages,
slideCard,
summary,
},
revalidate: 2,
};
};
Type Definitions:
interface SanityBody {
_createdAt: string;
_id: string;
_rev: string;
_updatedAt: string;
}
export interface Image extends SanityBody {
_type:"image";
asset: {
_ref: string;
_type: "reference"
};
}
export interface Card extends SanityBody {
_type: "card";
title: string;
image: Image;
description:Text;
}
export interface Banner extends SanityBody {
_type: "banner";
title: string;
image: Image;
}
export interface Pages extends SanityBody {
_type: "pages"
page1: Image;
}
export interface CardList extends SanityBody {
_type: "cardList"
thumbnail:Image;
title:string;
author:string;
chapter:string;
subtitle:string;
date:string;
}
export interface SlideCard extends SanityBody {
_type: "slideCard"
image:Image;
title:string;
chapter:string;
}
export interface Summary extends SanityBody {
_type: "summary"
title:string;
author:string;
description:Text;
}
export interface Chapter extends SanityBody {
_type: "chapter"
title:string;
date:string;
}
card schema:
export default {
name: 'card',
title: 'Card',
type: 'document',
fields: [
{
name: 'thumbnail',
title: 'Thumbnail',
type: 'image',
},
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'description',
title: 'Description',
type: 'text',
},
],
}
getCard:
fetching data on the front-end
//Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type {NextApiRequest, NextApiResponse} from "next";
import {groq} from "next-sanity";
import {sanityClient} from "sanity";
import { Card } from "typings";
const query = groq`
*[_type == "card"]
`
type Data = {
card: Card[];
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
const card: Card[] = await sanityClient.fetch(query);
res.status(200).json({ card })
}
fetchCard:
fetching data on the back-end
import {Card} from "typings";
export const fetchCard = async() => {
const res = await fetch (`${process.env.NEXT_PUBLIC_BASE_URL}/api/getCard`);
const data = await res.json();
const card: Card[] = data.card;
return card;
};

Related

React has no exported member

I am writing a component with react typescript, but when I am trying to use it, it kept saying there is no exported member
here is my component file:
import type { FunctionComponent } from "react";
interface TitleProps{
title: string;
subtitle: string;
}
const Title: FunctionComponent<TitleProps> = ({title, subtitle}) => {
return (
<>
<h1>{title}</h1>
<h2>{subtitle}</h2>
</>
);
};
export default Title;
and here is the page I tried to use this component:
import { Title } from "#neuralbertatech/react";
import Head from "next/head";
import type { NextPage } from "next";
const Home: NextPage = () => {
return (
<>
<Head>
<title>Test</title>
</Head>
<main>
<Title title="big title" subtitle="small title" />
</main>
</>
);
};
export default Home;
here is the error:
'''
Module '"#neuralbertatech/react"' has no exported member 'Title'.ts(2305)
'''
and the Title.tsx is in this Module #neuralbertatech/react for sure.

Error fetching json file into Next.js from local Nest.js app

I'm really new with Next.js and Nest.js and I can't figure out what's going wrong here.
I have a backend nest.js app serving a json api on http://localhost:3081/v1/transactions.
If I try to do a GET request from postman all works fine.
This is my index.tsx in the next.js frontend app:
import type { GetStaticProps, NextPage } from "next";
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
import { GetTransactionsResults, Transaction } from "../transactions.types";
const Home: NextPage<{ transactions: Transaction[] }> = ( { transactions }) => {
return (
<div className={styles.container}>
<main className={styles.main}>
<Image src={"/logo.png"} width={120} height={32} />
{transactions.map((transaction) => {
return <li key={ transaction.id }>{ transaction.asset }</li>
})}
</main>
</div>
);
};
export const getStaticProps: GetStaticProps = async (context) => {
const res = await fetch("http://localhost:3081/v1/transactions");
const { results }: GetTransactionsResults = await res.json();
return {
props: {
transactions: results,
},
};
};
export default Home;
and this is the Interface in transaction.type.ts:
export interface GetTransactionsResults {
info: Info;
results: Transaction[];
}
export interface Info {
count: number;
page: number;
next: string;
prev: null;
}
export enum TransactionNature {
Deposit = "Deposit",
Withdraw = "Withdraw",
Rewards = "Rewards",
Interest = "Interest",
}
export interface Transaction {
id: string
nature: {
code: TransactionNature
}
amount: number
asset: string
user: {
id: string
}
}
So if I try to load the frontend I get this error message:
Server Error
Error: Error serializing `.transactions` returned from `getStaticProps` in "/".
Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit this value.
It seems like an empty response from the backend app...
I also tried to fetch data from another web api like this one: https://rickandmortyapi.com/api/character/ and it works.
Sure I miss something here, sorry if it is a dumb question but I'm really new.
Ok I figured out how to solve it.
I followed the documentation and rewrite the function in this way:
import type { NextPage } from "next";
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
import { GetTransactionsResults, Transaction } from "../transactions.types";
const Home: NextPage<{transactions: Transaction}> = ( { transactions } ) => {
return (
<div className={styles.container}>
Object.values(transactions).map(transaction => {
return <li key={transaction.id}>{transaction.asset}</li>
})
}
</div>
);
};
//Get API data
export async function getStaticProps() {
// Call an external API endpoint to get posts.
// You can use any data fetching library
const res = await fetch('http://localhost:3081/v1/transactions');
const results: GetTransactionsResults = await res.json()
// By returning { props: { transactions } }, the Home component
// will receive `transactions` as a prop at build time
return {
props: {
transactions: results,
},
}
}
export default Home;

Can't render data from api call from one component to another in Angular 8

I am new to Angular and I am facing issue in rendering data in UI from an api call. I want to show the data received as response in the parent and show it in a component called webex-uptime-chart.
The file with API call is as shown below:
public uptimeChartConfig: Array<{ [key: string]: string | any }>;
this.uptimeChartConfig = [
{
rpcMethod: 'getNodeStatus',
node: this.NodeId,
duration: '10 mins'
},
];
// API call to get the Uptime Chart data
this.uptimeChartConfig
.filter(config => config.rpcMethod)
.map(config => {
return this.rpcService
.invoke({
method: 'getNodeStatus',
args: ['2d945891-be9b-46a8-973e-3f343a8999ad'],
})
.then((data: any) => {
if (data && data.response) {
const labels: Array<string> = data.response.map(value =>
this.datePipe.transform(value.epochtime * 1000, 'shortTime')
);
const nodeList = {};
data.response.forEach(node => {
if (nodeList[node.nodeId]) {
nodeList[node.nodeId] = [...nodeList[node.nodeId], node.uptime];
} else {
nodeList[node.nodeId] = [node.uptime];
}
});
this.lineChartData[config.rpcMethod] = {
labels: labels,
dataSets: nodeList,
};
} else {
this.lineChartData[config.rpcMethod] = {
lables: [],
dataSets: [],
};
}
});
The response looks as shown below:
The parent component's html where the webex-uptime-chart is called looks as shown below:
<webex-uptime-chart
*ngFor="let config of uptimeChartConfig"
[config]="config"
[incomingData]="lineChartData[config.rpcMethod]">
</webex-uptime-chart>
The webex-uptime-chart.ts component file is:
import { Component, Input, OnInit } from '#angular/core';
#Component({
selector: 'webex-uptime-chart',
templateUrl: './uptime-chart.component.html',
styleUrls: ['./uptime-chart.component.scss']
})
export class UptimeChartComponent implements OnInit {
#Input() chartData: any[];
#Input() public config;
#Input() public incomingData: any;
public labels: Array<string> = [];
public dataSets: any = {};
constructor() { }
ngOnInit() {
this.labels = this.incomingData.labels;
this.dataSets = this.incomingData.dataSets;
}
}
The webex-uptime-chart.html file is:
<div class="uptime-container">
<ul *ngFor="let data of chartData">
<li [ngClass]="data.status === 'down' ? 'my-class red-circle' : 'my-class green-circle '">
<span>{{ config.node }}</span>
</li>
<p class="right-text">{{ config.duration }}</p>
<hr />
</ul>
</div>
I get the below error while trying to run :
I don't know how to proceed.
incomingData is asynchronous. As a result it is initially provided as undefined to the child component until the promise then callback was executed. But this change is not registered within child component, since you only read incomingData within ngOnInit.
You could use ngOnChanges instead of ngOnInit.
ngOnChanges(changes: SimpleChanges) {
if (changes['incomingData'] && !!changes['incomingData'].previousValue) {
this.labels = changes['incomingData'].currentValue.labels;
this.dataSets = changes['incomingData'].currentValue.dataSets;
}
}

How to bind rowdata of ag-grid inside gridoption using a httpservice

I am using ag-grid license edition and want to bring record set to the grid using a service. I am using Ag-Grid gridoption property and initializing rowdata
in the constructor of the component.ts class. But the data is not rendering. No error either. Please have a look of my component.ts class.
Please note: the web api is returning the json data correctly and the service in Angular is tested sucessfully without Ag-Grid
import {Component, OnInit} from "#angular/core";
import {GridOptions} from "ag-grid";
import {RedComponentComponent} from "../red-component/red-component.component";
import { person } from "../Shared/models/person.model";
import {personservice} from '../service/person.service';
#Component({
selector: 'app-my-grid-application',
templateUrl: './my-grid-application.component.html'
})
export class MyGridApplicationComponent implements OnInit{
private gridOptions: GridOptions;
private persons: person[];
constructor(private personservice: personservice) {
this.gridOptions = <GridOptions>{};
this.gridOptions.columnDefs = [
{
headerName: "ID",
field: "PersonId",
width: 100
},
{
headerName: "Name",
field: "PersonNm",
cellRendererFramework: RedComponentComponent,
width: 100
},
{
headerName: "Email",
field: "PersonEmail",
cellRendererFramework: RedComponentComponent,
width: 100
}
];
this.gridOptions.rowData = this.persons
}
ngOnInit() {
this.personservice.findAll().subscribe(
persons => {
this.persons = persons
},
error => {
console.log(error);
}
)
}
}
Instead of providing columnDefs and rowData with gridOptions, try providing them directly like this.
<ag-grid-angular
[gridOptions]="gridOptions"
[rowData]="rowData"
[columnDefs]="columnDefs"
>
</ag-grid-angular>
Also, declare columnDefs and rowData as component variables, and then assign them after getting the response.
rows: any[] = [];
columnDefs: ColDef[];
constructor(private personservice: personservice) {
this.gridOptions = <GridOptions>{};
this.columnDefs = [
// your column definition goes here
];
}
ngOnInit() {
this.personservice.findAll().subscribe(
persons => {
this.rows = persons
},
error => console.log(error)
)
}
Let me know if you face any issue after this.

TypeError: Cannot read property 'map' of undefined with Angular v6

For some reason the response JSON is not mapping correctly
Here is my html.
profile-search.component.html
<h3>Enter Username</h3>
<input (keyup)="search($event.target.value)" id="name" placeholder="Search"/>
<ul>
<li *ngFor="let package of packages$ | async">
<b>{{package.name}} v.{{package.repos}}</b> -
<i>{{package.stars}}</i>`enter code here`
</li>
</ul>
Here is component that the html pulls from.
profile-search.component.ts
import { Component, OnInit } from '#angular/core';
import { Observable, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
import { NpmPackageInfo, PackageSearchService } from './profile-search.service';
#Component({
selector: 'app-package-search',
templateUrl: './profile-search.component.html',
providers: [ PackageSearchService ]
})
export class PackageSearchComponent implements OnInit {
withRefresh = false;
packages$: Observable<NpmPackageInfo[]>;
private searchText$ = new Subject<string>();
search(packageName: string) {
this.searchText$.next(packageName);
}
ngOnInit() {
this.packages$ = this.searchText$.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap(packageName =>
this.searchService.search(packageName, this.withRefresh))
);
}
constructor(private searchService: PackageSearchService) { }
toggleRefresh() { this.withRefresh = ! this.withRefresh; }
}
Service that component pulls from.
profile-search.service.ts
import { Injectable, Input } from '#angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { HttpErrorHandler, HandleError } from '../http-error-handler.service';
export interface NpmPackageInfo {
name: string;
}
export const searchUrl = 'https://api.github.com/users';
const httpOptions = {
headers: new HttpHeaders({
'x-refresh': 'true'
})
};
function createHttpOptions(packageName: string, refresh = false) {
// npm package name search api
// e.g., http://npmsearch.com/query?q=dom'
const params = new HttpParams({ fromObject: { q: packageName } });
const headerMap = refresh ? {'x-refresh': 'true'} : {};
const headers = new HttpHeaders(headerMap) ;
return { headers, params };
}
#Injectable()
export class PackageSearchService {
private handleError: HandleError;
constructor(
private http: HttpClient,
httpErrorHandler: HttpErrorHandler) {
this.handleError = httpErrorHandler.createHandleError('HeroesService');
}
search (packageName: string, refresh = false): Observable<NpmPackageInfo[]> {
// clear if no pkg name
if (!packageName.trim()) { return of([]); }
// const options = createHttpOptions(packageName, refresh);
// TODO: Add error handling
return this.http.get(`${searchUrl}/${packageName}`).pipe(
map((data: any) => {
return data.results.map(entry => ({
name: entry.any[0],
} as NpmPackageInfo )
)
}),
catchError(this.handleError('search', []))
);
}
}
I have tried to alter
return this.http.get(`${searchUrl}/${packageName}`).pipe(
map((data: any) => {
return data.results.map(entry => ({
name: entry.any[0],
} as NpmPackageInfo )
)
to
login: data.login, and login: entry.login but keep getting the below error.
http-error-handler.service.ts:33 TypeError: Cannot read property 'map'
of undefined
at MapSubscriber.project (profile-search.service.ts:49)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next
(map.js:75)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next
(map.js:81)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/operators/filter.js.FilterSubscriber._next
(filter.js:85)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber.notifyNext
(mergeMap.js:136)
at InnerSubscriber.push../node_modules/rxjs/_esm5/internal/InnerSubscriber.js.InnerSubscriber._next
(InnerSubscriber.js:20)
at InnerSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
results in data.results is probably undefined, check that the data object matches the schema you're expecting it to.
map working on array but this.http.get(${searchUrl}/${packageName}) return object not array.
so data.results is undefined.
This is how I converted my object into an array, if anyone has a better way of doing please let me know.
return this.http.get(`${searchUrl}/${packageName}`).pipe(
map((data: any) => {
console.log(data);
var profile = Object.keys(data).map(function(key) {
return [(key) + ': ' + data[key]];
}
);
console.log(profile);
data = profile;
return data;
}),
catchError(this.handleError<Error>('search', new Error('OOPS')))
);
}
}
I fixed this issue by eliminating ".results"
from
.map((data: any) => this.convertData(data.results))
to
.map((data: any) => this.convertData(data))
To avoid the error, change
map((items) => items.map
to
map((items) => items?.map
Then set your result set as an empty array:
this.list = data ?? [];
PS: Used with Angular 14. In older versions you may need to change last one to data ? data : []