Import image to a component from React project - javascript

I'm building an app with React and Typescript.
I'm retrieving data using a free API. I'm trying to use a default image for the objects that do not have them.
This is the structure of my project:
In movies.service.tsx I fetch the data and assign to the property picture of movie object the value retrieved from the DB (in case there is no value, I would like to assign it the path of default-poster.png):
import * as img from '../images/default-poster.png';
console.log('img ', img);
const movieApiBaseUrl = "https://api.themoviedb.org/3";
const posterBaseUrl = "https://image.tmdb.org/t/p/w300";
export interface Movie {
id: number;
title: string;
rating: number;
description: string;
picture?: string;
date: string;
}
export function fetchMovies(): Promise<Movie[]> {
return fetch(
`${movieApiBaseUrl}/discover/movie?sort_by=year.desc&api_key=${process.env.REACT_APP_API_KEY}`
)
.then((res) => res.json())
.then((res) => mapResult(res.results))
.catch(() => {
return [];
});
}
// = movie has to be after const {} here
function mapResult(res: any[]): Movie[] {
return res.map((movie) => {
const {
id,
title,
vote_average,
overview,
poster_path,
date,
} = movie;
return {
id: id,
title: title,
rating: vote_average,
description: overview,
picture: poster_path ? `${posterBaseUrl}${poster_path}` : img,
date: date,
};
});
}
However, I was not allowed to assign img to picture property by Typescript. I have also consoled out img value and it is equal to a module:
Module default: "data:image/png;base64,iVBORw0KGgoAAAA <...>" Symbol(Symbol.toStringTag): "Module" esModule: true __proto: Object
I need to assign the paths of images to picture property so that I could use them in MovieCards.tsx component later on.
What should I change?
Thanks!

The solution is importing the default image to movies.service.tsx:
import noImage from '../images/no-image-available.png';
and then passing the variable noImage as the third operand of ternary operator:
picture: poster_path ? `${posterBaseUrl}${poster_path}` : noImage,

Related

Server Error, error serializing `getServerSideProps`

My console shows me that there is a problem with serving, which I can not solve:
Uncaught Error: Error serializing .title returned from getServerSideProps in "/property/[slug]".
Reason: undefined cannot be serialized as JSON. Please use null or omit this value.
I am using sanity and next.js
This is my code from the slug component:
export const getServerSideProps = async (pageContext) => {
const pageSlug = pageContext.query.slug
const query = `*[-type == "property" && slug.current == $pageSlug][0]{
title,
location,
propertyType,
mainImage,
images,
pricePerNight,
beds,
bedrooms,
description,
host->{
_id,
name,
slug,
image
},
reviews[]{
...,
traveller->{
_id,
name,
slug,
image
}
}
}`
const property = await sanityClient.fetch(query, { pageSlug})
if (!property) {
return {
props: null,
notFound: true,
}
} else {
return {
props: {
title: property.title,
location: property.location,
propertyType: property.propertyType,
mainImage: property.mainImage,
images: property.images,
pricePerNight: property.pricePerNight,
beds: property.beds,
bedrooms: property.bedrooms,
description: property.description,
host: property.host,
reviews: property.reviews
}
}
}
}
export default Property
In my terminal, the client and server compiled successfully.
I tried to return JSON.stringify but still had no success.
According to Next.js documentation, props object should be serializable to be fetched correctly by your rendered site. undefined values (just like functions) are not serializable.
You can provide null fallback values for props which can be undefined:
export const getServerSideProps = () => {
// some fetching logic
return {
props: {
title: property.title || null
// rest of props
}
};
}

Assign a property of nested array inside a new string array

I'm new in VueJs and Typescript, so I have four interfaces:
export interface ShipMethodResponse {
companyTypeList: CompanyType[]
}
export interface CompanyType {
companyTypeId: string
companyTypeName: string
companyList: Company[]
}
export interface Company {
companyId: string
companyTypeId: string
companyName: string
companyAbbreviation: string
companyDescription: string
companyWebsite: string
shipMethodList: ShipMethod[]
}
export interface ShipMethod {
shipMethodId: number
companyId: string
shipMethodName: string
}
Each one can have an array of the next interface if you read from top to down.
So I want to insert into a new array of a string the property companyName of Company interface, so I try:
data() {
return {
shipMethodList: [] as string[],
...
}
},
methods: {
async myMethod() {
//companyTypeList is a CompanyType array
var b = companyTypeList.map((e) => ({
companyList: e.companyList,
}))
for (const c of b) {
var company = c.companyList.map((company) => ({
companyName: company.companyName,
}))
this.shipMethodList.push(company)
}
}
}
But when I try to push the company it is throwing
Argument of type '{ companyName: string; }[]' is not assignable to
parameter of type 'string'.
How can I create a list of all "companyName" property? Regards
I think the problem is here:
var company = c.companyList.map((company) => ({
companyName: company.companyName,
}))
You say you want to create string[], but that map function creates { companyName: string }[]
Change it to this:
var allCompanyNames = c.companyList.map(
company => company.companyName
)
UPDATE
What you really want is probably this:
for (const c of b) {
for(company of c.companyList) {
this.shipMethodList.push(company.companyName)
}
}

How do I set up typescript in Redux toolkit?

I want to receive data from redux toolkit's createAsyncThunk when dispatching.
But I don't know how to set the data type.
If no data type is specified, a warning line is displayed with a red line.
like this Screenshot
How do I specify the type?
this is my code
// commentinput is string and post.id is number
const commetsubmitfun = useCallback(() => {
dispatch(addComment({content: commentinput, postId: post.id}));
}, [dispatch, commentinput]);
export const addComment = createAsyncThunk(
'post/addComment',
async (data, {rejectWithValue}) => {
try {
// data: {content: "aaa", postId: 66}
const response = await axios.post(`/post/${data.postId}/comment`, data); // POST /post/1/comment
return response.data;
} catch (error: any) {
return rejectWithValue(error.response.data);
}
},
);
You should declare type when calling createAsyncThunk ,
declare an interface for data
like this :
type DataType = {
content : string
postId : string
}
then add it here :
async (data : DataType, {rejectWithValue}) => {
You can read more here : https://redux-toolkit.js.org/usage/usage-with-typescript#createasyncthunk
you specify the types in the createSlice file with either interface or type
eg:
interface Action {
type: string
payload: {
img: string
images: string[] | [] | null
}
}
type is always string, payload is what you put in the { } inside dispatch(addComment({content: ...payload, postId: ..payload}));
interface Action {
type: string
payload: {
content: string
postId: number //or if its possibly undefined/null postId?: number | null | undefined
}
}
const initialStateValue = {
post: null
}
reducers: {
addComment: (state: any = initialStateValue, action: Action) => {
state.post = action.payload;
},

Saving a many to many column in postgres using typeorm

I have an entity of products which looks like
#Entity('products')
export class productsEntity extends BaseEntity{
#PrimaryGeneratedColumn()
id: number;
//..columns
#ManyToMany( type => Categories, categoryEntity => categoryEntity.products)
categories: string;
}
Then i have an entity called category
#Entity('Categories')
export class Categories extends BaseEntity{
#PrimaryGeneratedColumn()
id: number;
#Column({nullable: false, default: 'all', unique: true})
title: string;
#ManyToMany(()=> productsEntity, product => product.categories)
products: productsEntity[];
}
Also i have a DTO to validate.
export class addProductDto{
// other DTO'S
#IsNotEmpty({ message: "category needs to be set."})
categories: Categories[];
}
Now when i try to save a new product in products table everything seems to work fine except categories column.
#EntityRepository(productsEntity)
export class productsRepository extends Repository<productsEntity> {
private connection: Connection
private logger = new Logger();
async addProduct(productDetails, username){
const {title, description, belongsTo, price, units} = productDetails;
try{
let newProduct = new productsEntity();
newProduct.title = title;
newProduct.description = description;
newProduct.categories = belongsTo
newProduct.price = price;
newProduct.units = units;
newProduct.soldBy = username;
await this.manager.save(newProduct);
}
catch(err){
this.logger.error(err.message);
throw new HttpException('Failed adding Product.', HttpStatus.INTERNAL_SERVER_ERROR)
}
}
}
What am i doing wrong here??
All the fields get saved but categories doesn't.
first, you have to #JoinTable at the products entity and also use the cascades option to save both sides with one save command the last thing is the type of categories is Categories[]
#Entity('products')
export class productsEntity extends BaseEntity{
#PrimaryGeneratedColumn()
id: number;
//..columns
#ManyToMany( type => Categories, categoryEntity => categoryEntity.products , {cascade : true ,})
#JoinTable({name : 'products-catigories'})
categories: Categories[];
finally it will works fine
if you want to import it => use QueryBuilder in your service or repository
just change the $ID with the product id or catigory id
import { getRepository } from "typeorm";
public async getProducts(id) {
let query = getRepository(productsEntity)
.createQueryBuilder('product')
.where('product.id = : id' , {id : $ID})
.leftJoinAndSelect('product.categories' , 'catigories')
const product = query.getOne()
return product
}
import { getRepository } from "typeorm";
public async getCatigories(id) {
let query = getRepository(Catigories)
.createQueryBuilder('catigory')
.where('catigory.id = : id' , {id : $ID})
.leftJoinAndSelect('catigory.products' , 'products')
const product = query.getOne()
return product
you also can use find Options and its an easier way
const getOneProduct= await this.entity.findOne(id , {relations : ["categories"]})
const getAllProducts= await this.entity.find({relations : ["categories"]})
it will add the categories to the product result

What can I do to let the typescript type system know the type of the return value?

I am new to typescript, I am trying to migrate so code from js to ts while reading the ts HandBook.
Here is the relationship between each level developer and user:
lib developer -> ProductProvider ->
product developer -> Product ->
product user -> robot
It seems going well, except I have no idea how to tel typescript the type of the robot, which is the type of assembler function return value, also the type of Product function return value.
interface Injection {
[index: string]: string
}
interface Component {
id: string,
install: (injection: Injection) => void
}
interface InitOptions {
id: string,
screenType: string,
SoC: string,
components: Component[],
}
type Assembler = (injection: object, options: object) => unknown;
type ProductProvider = (initOptions: InitOptions, assembler: Assembler) => (options: object) => ReturnType<typeof assembler>
function ProductProvider(initOptions: InitOptions, assembler: Assembler): (options: object) => ReturnType<typeof assembler> {
//some work to init
const installedInjection: Injection = {};
initOptions.components.forEach((component => component.install(installedInjection)));
return function Product(startOption: object): ReturnType<typeof assembler> {
return assembler(installedInjection, startOption);
}
}
export default ProductProvider;
const assembler: Assembler = (injection: object, options: object) => ({ injection, options });
const Product = ProductProvider({
id: 'XMC9E8DCO5EXEU',
screenType: 'LCD',
SoC: 'RX-78',
components: [{
id: 'component1',
install(injection) {
//some work
const content = 'whatever';
injection[this.id] = content;
}
}]
}, assembler);
const robot = Product({ battery: 'A' });
In type Assembler, because the user of ProductProvider is freedom on how to assemble, so I think the type of function will return unknown.
But in fact, the Product developer know that the assemble parameter passed to ProductProvider, it return a value, and it type is object.
And other Product developers may also return another Interface or Type.
What can I do to let the typescript type system know the type of the return value? And then we can enjoy intellisense.
XD
type Assembler<T> = (injection: object, options: object) => T;
type ProductProvider<T> = (initOptions: InitOptions, assembler: Assembler<T>) => (options: object) => T;
done.
enter image description here

Categories

Resources